A simple Express.js server with S3-compatible file upload functionality. Supports AWS S3 and S3-compatible storage services like MinIO, DigitalOcean Spaces, Cloudflare R2, and others.
- ✅ Express.js server with file upload endpoint
- ✅ Web-based upload interface with drag & drop
- ✅ S3-compatible storage integration
- ✅ File validation and size limits
- ✅ Upload progress tracking
- ✅ Unique filename generation
- ✅ CORS support
- ✅ Environment-based configuration
- ✅ Health check endpoint
- ✅ Error handling
- Node.js (v14 or higher)
- npm or yarn
- S3-compatible storage account and credentials
-
Clone and setup
cd s3-upload-test npm install
-
Configure environment
cp .env.example .env # Edit .env with your credentials
-
Start the server
npm start # or for development npm run dev
-
Test the upload
# Open browser and go to http://localhost:3000 # Or test via curl curl -X POST -F "file=@your-file.jpg" http://localhost:3000/upload
Copy .env.example
to .env
and configure your credentials:
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
S3_BUCKET=your-bucket-name
# Leave S3_ENDPOINT empty for AWS S3
S3_ENDPOINT=
S3_FORCE_PATH_STYLE=false
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_REGION=us-east-1
S3_BUCKET=test-bucket
S3_ENDPOINT=http://localhost:9000
S3_FORCE_PATH_STYLE=true
AWS_ACCESS_KEY_ID=your_spaces_key
AWS_SECRET_ACCESS_KEY=your_spaces_secret
AWS_REGION=nyc3
S3_BUCKET=your-space-name
S3_ENDPOINT=https://nyc3.digitaloceanspaces.com
S3_FORCE_PATH_STYLE=false
AWS_ACCESS_KEY_ID=your_r2_access_key
AWS_SECRET_ACCESS_KEY=your_r2_secret_key
AWS_REGION=auto
S3_BUCKET=your-r2-bucket
S3_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
S3_FORCE_PATH_STYLE=false
Serves the web upload interface when accessed from a browser, or returns server information as JSON when accessed programmatically.
Browser Response: Returns the HTML upload interface with drag & drop functionality.
API Response:
{
"message": "S3 File Upload Server",
"endpoints": {
"upload": "POST /upload - Upload a file to S3",
"health": "GET /health - Health check",
"ui": "GET / - Upload interface"
}
}
Health check endpoint.
Response:
{
"status": "OK",
"timestamp": "2023-10-06T12:00:00.000Z"
}
Upload a file to S3-compatible storage.
Request:
- Method:
POST
- Content-Type:
multipart/form-data
- Body: Form data with
file
field
Example with curl:
curl -X POST -F "file=@example.jpg" http://localhost:3000/upload
Example with JavaScript:
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('http://localhost:3000/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
Success Response:
{
"message": "File uploaded successfully",
"file": {
"originalName": "example.jpg",
"size": 123456,
"mimeType": "image/jpeg",
"s3Key": "1696608000000_a1b2c3d4_example.jpg",
"location": "https://your-bucket.s3.amazonaws.com/1696608000000_a1b2c3d4_example.jpg"
}
}
Error Response:
{
"error": "No file provided"
}
- Size Limit: 1GB (configurable in
server.js
) - Storage: Files are stored in memory temporarily and then uploaded to S3
- Filename Generation: Automatic unique filename with timestamp and hash
- Metadata: Original filename, upload date, and file size are stored as S3 metadata
- Start the server:
npm start
- Open your browser and go to
http://localhost:3000
- Use the drag & drop interface or click to select a file
- Click "Upload File" and watch the progress
- View the upload results and file details
# Upload a file
curl -X POST -F "file=@test.jpg" http://localhost:3000/upload
# Health check
curl http://localhost:3000/health
- Create a new POST request to
http://localhost:3000/upload
- Go to Body → form-data
- Add key
file
with typeFile
- Select your file and send
<!DOCTYPE html>
<html>
<head>
<title>File Upload Test</title>
</head>
<body>
<form action="http://localhost:3000/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Upload</button>
</form>
</body>
</html>
npm start
- Start the production servernpm run dev
- Start with nodemon for developmentnpm test
- Run tests (not implemented yet)
s3-upload-test/
├── public/
│ └── index.html # Web upload interface
├── server.js # Main Express server
├── s3-client.js # S3 client configuration and utilities
├── package.json # Dependencies and scripts
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
└── README.md # This file
The server handles various error scenarios:
- No file provided (400)
- File too large (400)
- S3 upload failures (500)
- Invalid endpoints (404)
- Server errors (500)
- Files are validated for size limits
- CORS is enabled (configure as needed)
- Environment variables protect sensitive credentials
- Consider adding file type validation for production use
- Implement authentication/authorization as needed
-
"Access Denied" errors
- Check your AWS credentials and permissions
- Ensure the bucket exists and is accessible
- Verify the bucket policy allows uploads
-
Connection timeouts
- Check your S3_ENDPOINT configuration
- Verify network connectivity to the S3 service
- For local MinIO, ensure it's running
-
"Bucket not found" errors
- Verify the bucket name in your
.env
file - Ensure the bucket exists in the specified region
- Verify the bucket name in your
-
CORS errors in browser
- The server includes CORS headers
- For production, configure CORS origins appropriately
Add console logging to troubleshoot issues:
// Add to server.js for debugging
app.use((req, res, next) => {
console.log(`${req.method} ${req.path}`, req.body);
next();
});
Feel free to submit issues and enhancement requests!
MIT License