- Go 67.7%
- Shell 8.7%
- JavaScript 7%
- PowerShell 6.6%
- HTML 5.1%
- Other 4.9%
|
Some checks failed
Lint / Lint (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Build and Push Docker Image / tag (push) Has been cancelled
Test / Test with Coverage (push) Has been cancelled
Build and Push Docker Image / build-amd64 (push) Has been cancelled
Build and Push Docker Image / build-arm64 (push) Has been cancelled
Build and Push Docker Image / create-manifest (push) Has been cancelled
Build and Push Docker Image / create-release (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Update all project-hosting URLs, container registry references, and GCS-centric website copy to reflect the migration to Forgejo and S3-compatible storage. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| deployment | ||
| docs | ||
| scripts | ||
| testdata | ||
| website | ||
| .gitignore | ||
| config.go | ||
| config_coverage_test.go | ||
| config_test.go | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| headers_test.go | ||
| interfaces.go | ||
| LICENSE.md | ||
| logging.go | ||
| logging_test.go | ||
| main.go | ||
| main_test.go | ||
| metrics.go | ||
| metrics_test.go | ||
| object_store_test.go | ||
| README.md | ||
| redirects_test.go | ||
| s3.go | ||
| server.go | ||
| server_coverage_test.go | ||
| server_integration_test.go | ||
| server_setup.go | ||
| server_setup_enhanced_test.go | ||
| server_setup_test.go | ||
| server_test.go | ||
Spray
Spray is a minimal Go web server that serves static files from S3-compatible object storage (such as minio or AWS S3). It also supports Google Cloud Storage as an alternative backend.
Features
- Simple and lightweight
- S3-compatible storage as default backend (minio, AWS S3, etc.)
- Google Cloud Storage support (optional)
- Prometheus metrics
- Custom redirects support
- HTTP cache with configurable rollout
- Health check endpoints
- Configurable port
Configuration
Environment Variables
Storage Backend
| Variable | Description | Default |
|---|---|---|
STORAGE_BACKEND |
Storage backend to use: s3 or gcs |
s3 |
BUCKET_NAME |
Name of the bucket to serve files from | (required) |
S3 Backend (STORAGE_BACKEND=s3)
| Variable | Description | Default |
|---|---|---|
S3_ENDPOINT |
S3-compatible endpoint URL (e.g. http://minio:9000) |
(AWS default) |
S3_REGION |
S3 region | us-east-1 |
AWS_ACCESS_KEY_ID |
AWS/S3 access key | (from environment/IAM) |
AWS_SECRET_ACCESS_KEY |
AWS/S3 secret key | (from environment/IAM) |
GCS Backend (STORAGE_BACKEND=gcs)
| Variable | Description | Default |
|---|---|---|
GOOGLE_PROJECT_ID |
Google Cloud project ID | (required for GCS) |
GOOGLE_APPLICATION_CREDENTIALS |
Path to GCP service account JSON | (from environment) |
Logging
| Variable | Description | Default |
|---|---|---|
LOGGING_BACKEND |
Logging backend: zap or gcp |
zap |
Zap produces structured JSON logs to stderr. GCP logging requires valid Google Cloud credentials and is only useful when running on GCP.
Other
| Variable | Description | Default |
|---|---|---|
SPRAY_POWERED_BY_HEADER |
Custom X-Powered-By header value (empty string disables) | spray/<version> |
STORAGE_MOCK |
Set to true for a built-in mock store (debugging only) |
false |
Metrics
The following Prometheus metrics are exposed at /metrics:
spray_requests_total- Total HTTP requests, labeled by bucket, path, method and statusspray_request_duration_seconds- Request duration histogramspray_bytes_transferred_total- Total bytes transferredspray_active_requests- Currently active requestsspray_cache_total- Cache hit/miss/bypass counterspray_errors_total- Errors by typespray_object_size_bytes- Served object sizesspray_storage_operation_duration_seconds- Storage operation latency
Custom Redirects
Configure redirects by creating a .spray/redirects.toml file in your bucket:
[redirects]
"/old-path" = "https://example.com/new-path"
"/another-path" = "https://example.com/destination"
Redirects take precedence over files at the same path. The server returns a 302 Found response.
Inspect the current redirect configuration at /config/redirects:
{
"redirects": {
"/old-path": "https://example.com/new-path",
"/source": "https://git.brooktrails.org/picotechllc/spray"
},
"count": 2,
"config_source": ".spray/redirects.toml",
"bucket_name": "your-bucket-name"
}
X-Powered-By Header
Spray adds an X-Powered-By header to responses. Control it with:
- Server admin: Set
SPRAY_POWERED_BY_HEADERenv var (empty string disables entirely) - Site owner: Create
.spray/headers.tomlin your bucket with[powered_by]/enabled = false
Server admin settings take precedence. If the env var disables the header, site owners cannot re-enable it.
Endpoints
/- Serves static files from the configured bucket/metrics- Prometheus metrics/readyz- Readiness probe/livez- Liveness probe/config/redirects- Current redirect configuration (JSON)
Usage
With minio (S3-compatible)
docker run \
-e BUCKET_NAME=my-site \
-e S3_ENDPOINT=http://minio:9000 \
-e AWS_ACCESS_KEY_ID=minioadmin \
-e AWS_SECRET_ACCESS_KEY=minioadmin \
-p 8080:8080 \
git.brooktrails.org/picotechllc/spray:latest
With AWS S3
docker run \
-e BUCKET_NAME=my-site \
-e S3_REGION=us-west-2 \
-e AWS_ACCESS_KEY_ID=AKIA... \
-e AWS_SECRET_ACCESS_KEY=... \
-p 8080:8080 \
git.brooktrails.org/picotechllc/spray:latest
With Google Cloud Storage
docker run \
-e STORAGE_BACKEND=gcs \
-e BUCKET_NAME=my-site \
-e GOOGLE_PROJECT_ID=my-project \
-p 8080:8080 \
git.brooktrails.org/picotechllc/spray:latest
Building from source
git clone https://git.brooktrails.org/picotechllc/spray.git
cd spray
go build
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Website
The Spray project website is hosted using Spray itself at spray.picote.ch.
Contact
For any questions or suggestions, please open an issue.