A serverless music browser and streaming API built with Go, Gin, and AWS Lambda. Browse, search, and stream music files stored in S3 with a beautiful web interface and powerful REST API.
- Overview
- Features
- Quick Start
- Deployment
- Configuration
- API Endpoints
- Development
- Build Metadata
- Links
go-music provides a complete solution for browsing and streaming music files stored in AWS S3. It features:
- Interactive Web UI – Browse directories, search by title or folder, and stream audio directly from S3
- REST API – JSON endpoints for directory listing, search, and file operations
- Pre-signed URLs – Secure, time-limited audio streaming without exposing credentials
- Multi-format Support – Handles MP3, WAV, OGG, and MP4 audio files
- Flexible Deployment – Run on AWS Lambda, Docker, or standalone
The service automatically adapts to its environment, running as a Lambda function when AWS_LAMBDA_FUNCTION_NAME is detected or as a standard web server otherwise.
- 🎵 Music Streaming – Stream audio files from S3 using secure pre-signed URLs
- 🔍 Smart Search – Search by song title or directory name with real-time results
- 📁 Directory Browsing – Navigate your S3 music collection like a file browser
- 🎨 Modern UI – Responsive web interface with clean design
- ☁️ Lambda Ready – Auto-detects AWS Lambda environment with zero config changes
- 🐳 Docker Support – Containerized deployment with multi-arch builds (amd64/arm64)
- 🔐 Secure – Uses IAM roles and pre-signed URLs, never exposes credentials
- 🚀 Fast – Efficient S3 API usage with streaming support
- 📊 Build Metadata – Version, commit hash, and build time baked into releases
Requires Go 1.24+.
git clone https://github.com/johnwmail/go-music.git
cd go-music
# Set required environment variables
export BUCKET=your-s3-bucket-name
export AWS_REGION=us-east-1
export S3_PREFIX=music # optional
# Run the service
go run .Visit http://localhost:8080 to browse your music collection.
docker run -p 8080:8080 \
-e BUCKET=your-bucket \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=your-key \
-e AWS_SECRET_ACCESS_KEY=your-secret \
ghcr.io/johnwmail/go-music:latestBuild and run locally:
docker build -t go-music:local -f docker/Dockerfile .
docker run --rm -p 8080:8080 \
-e BUCKET=your-bucket \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=your-key \
-e AWS_SECRET_ACCESS_KEY=your-secret \
--name go-music go-music:localUsing Compose:
docker compose -f docker/docker-compose.yml up --buildMulti-arch support: Images are built for linux/amd64 and linux/arm64 automatically via GitHub Actions.
The app switches to Lambda mode when AWS_LAMBDA_FUNCTION_NAME is present. The deploy-lambda.yml workflow handles automated deployments.
-
Build the Lambda bootstrap binary:
go build \ -ldflags "-X main.Version=v1.0.0 -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) -X main.CommitHash=$(git rev-parse --short HEAD)" \ -tags netgo -trimpath \ -o bootstrap .
-
Package with static and templates assets:
mkdir -p lambda-artifacts mv bootstrap lambda-artifacts/ cp -r static lambda-artifacts/ cp -r templates lambda-artifacts/ cd lambda-artifacts && zip -r ../deployment.zip . && cd ..
-
Deploy via AWS CLI or Console with these environment variables:
BUCKET– Your S3 bucket nameS3_PREFIX– Optional prefix (e.g., "music")GIN_MODE– Set to "release" for production
Push to the deploy/lambda branch or manually trigger the workflow:
gh workflow run deploy-lambda.yml \
-f function_name=your-lambda-function-nameRequired GitHub secrets:
AWS_ACCESS_KEY_ID_DEPLOY_LAMBDAAWS_SECRET_ACCESS_KEY_DEPLOY_LAMBDAAWS_REGION
Required GitHub variables:
LAMBDA_FUNCTION_NAMEBUCKETS3_PREFIX(optional)LAMBDA_EXECUTION_ROLE
Pre-built images are available on GitHub Container Registry:
docker pull ghcr.io/johnwmail/go-music:latest
docker pull ghcr.io/johnwmail/go-music:v1.0.0 # specific versionThe service uses environment variables for configuration:
| Variable | Required | Default | Description |
|---|---|---|---|
BUCKET |
Yes | – | S3 bucket containing your music files |
AWS_REGION |
Recommended | auto-detect | AWS region for S3 bucket |
S3_PREFIX |
No | "" |
Optional prefix path in S3 (e.g., "music") |
AWS_ACCESS_KEY_ID |
Docker only* | – | AWS access key (use IAM role in Lambda) |
AWS_SECRET_ACCESS_KEY |
Docker only* | – | AWS secret key (use IAM role in Lambda) |
PORT |
No | 8080 |
HTTP server port (ignored in Lambda) |
GIN_MODE |
No | debug |
Set to "release" for production |
* Lambda deployments should use IAM roles instead of static credentials.
Your S3 bucket should contain audio files organized in directories:
my-music-bucket/
├── music/ # S3_PREFIX="music"
│ ├── Rock/
│ │ ├── song1.mp3
│ │ └── song2.mp3
│ └── Jazz/
│ └── tune.mp3
Required IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}| Method | Path | Description |
|---|---|---|
| GET | / |
Serves the web UI |
| GET | /static/* |
Serves static assets (CSS, JS) |
| POST | /api |
Main API endpoint (see functions below) |
| GET | /audio/*path |
Returns pre-signed S3 URL for streaming |
Send JSON payloads with a function field and relevant parameters:
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"dir","path":"Rock/"}'curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"searchTitle","searchStr":"love"}'curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"searchDir","searchStr":"jazz"}'curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"getAllMp3"}'curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"getAllDirs"}'# Get pre-signed URL (valid for 1 hour)
curl http://localhost:8080/audio/Rock/song.mp3
# Returns: {"url":"https://s3.amazonaws.com/..."}Sample API response:
{
"files": [
{
"name": "song.mp3",
"path": "Rock/song.mp3",
"size": 5242880,
"modified": "2024-01-15T10:30:00Z"
}
],
"directories": ["Rock", "Jazz", "Classical"]
}# Clone the repository
git clone https://github.com/johnwmail/go-music.git
cd go-music
# Install dependencies
go mod download
# Run tests (no AWS credentials required)
export MUSIC_DIR=/tmp/test-music
export GIN_MODE=release
go test -v ./...
# Run tests with coverage
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
go tool cover -html=coverage.out
# Format and lint
go fmt ./...
go vet ./...
golangci-lint run
# Run locally with live reload
go run .The test suite is designed to run without AWS/S3 credentials. Tests use local filesystem operations and mocked dependencies:
# Run all tests
MUSIC_DIR=/tmp/test-music GIN_MODE=release go test -v ./...
# Run specific test
MUSIC_DIR=/tmp/test-music go test -v -run TestIsAudioFile
# Run with race detection
MUSIC_DIR=/tmp/test-music go test -race ./...
# Generate coverage report
MUSIC_DIR=/tmp/test-music go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.outThe tests cover:
- ✅ Audio file detection (mp3, wav, ogg, mp4)
- ✅ JavaScript array encoding for web UI
- ✅ Version endpoint handler
- ✅ Local file system operations (listing, searching)
- ✅ Directory browsing and filtering
- ✅ Search functionality (case-insensitive)
The CI pipeline in .github/workflows/test.yml enforces code quality checks and runs the full test suite automatically.
go-music/
├── .github/
│ ├── instructions/ # Development guidelines
│ └── workflows/ # CI/CD pipelines
├── docker/
│ ├── Dockerfile # Multi-stage container build
│ └── docker-compose.yml # Local development setup
├── static/ # Web UI assets (HTML, CSS, JS)
├── main.go # Application entry point
├── go.mod # Go module definition
└── README.md
main.go exposes three build-time variables for versioning:
| Variable | Default | Purpose |
|---|---|---|
Version |
dev |
Semantic version or git tag |
BuildTime |
unknown |
Build timestamp (ISO 8601) |
CommitHash |
none |
Git commit SHA (short) |
Inject values with Go build flags:
go build \
-ldflags "-X main.Version=v1.2.3 \
-X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-X main.CommitHash=$(git rev-parse --short HEAD)" \
-o go-music .Values are logged on startup and accessible via the web UI.
- GitHub: https://github.com/johnwmail/go-music
- Container Images: https://github.com/johnwmail/go-music/pkgs/container/go-music
- Issues: https://github.com/johnwmail/go-music/issues
- Actions: https://github.com/johnwmail/go-music/actions
- Releases: https://github.com/johnwmail/go-music/releases
⭐ Star the project if this music streamer helps you out!