Skip to content

Administrator Manual

This guide covers installing, configuring, and operating Snackbox on a Linux host. The recommended deployment method is Docker Compose. A bare-metal systemd deployment is also supported for hosts without Docker.

Requirements

Platform

Requirement Notes
Linux x86-64 or arm64 Only supported deployment platform
Docker ≥ 24 + Compose v2 For container-based deployments (recommended)
systemd ≥ 232 For bare-metal service deployments
Reverse proxy nginx, Caddy, or similar — do not expose Snackbox directly to the internet

Resources

The figures below are based on benchmarks of the binary under moderate concurrent load (700 posts, 50 parallel read requests, 30 parallel write requests). Media storage is not included — plan disk separately based on expected upload volume.

Minimal Recommended
RAM 64 MB 128 MB
CPU 1 vCPU 2 vCPU
Disk — binary 20 MB 20 MB
Disk — database 100 MB 1 GB
Disk — media plan per upload volume

RAM: The process idles at ~16 MB RSS and peaks around 26 MB under concurrent load. 64 MB leaves comfortable headroom for the OS; 128 MB is appropriate for sustained high-traffic use.

Database: SQLite starts at under 10 KB and grows with content. Average storage is roughly 500 bytes per post for medium-length content — 10 000 posts use around 5 MB. Even a large archive stays well below 1 GB. SQLite does not load the entire database into RAM; it reads 4 KB pages on demand.

Media: Media files are stored at STORAGE_PATH and are not reflected in the database size. Allocate storage based on expected upload volume and back up DATABASE_PATH and STORAGE_PATH together.

Deploy

Pre-built images are published to the GitLab container registry:

registry.gitlab.com/cozybadgerde/applications/snackbox:latest
registry.gitlab.com/cozybadgerde/applications/snackbox:<version>

A ready-to-use docker-compose.yml is provided in the repository at deployments/docker/docker-compose.yml. The quickest way to get it is:

curl -LO https://gitlab.com/cozybadgerde/applications/snackbox/-/raw/trunk/deployments/docker/docker-compose.yml
curl -LO https://gitlab.com/cozybadgerde/applications/snackbox/-/raw/trunk/configs/.env.example
cp .env.example .env

1. Configure the environment

Edit .env and set at minimum:

JWT_SECRET=<random-string-min-32-characters>
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=<strong-password>

See the Configuration Reference below for all available variables.

2. Start the service

docker compose up -d

The container binds the API to 127.0.0.1:8080 and the metrics endpoint to 127.0.0.1:9091 by default. Place a reverse proxy in front of it for TLS and public access.

Useful commands

# Follow logs
docker compose logs -f

# Stop
docker compose down

# Update to a new image
docker compose pull
docker compose up -d

Binary (systemd)

A dedicated snackbox system user with no login shell and write access to /var/lib/snackbox is required.

1. Create the system user

sudo useradd --system --no-create-home --shell /sbin/nologin snackbox

2. Install the binary and migrations

Download the latest release binary for your architecture from the Releases page and install it:

sudo install -m 0755 snackbox-linux-amd64 /usr/local/bin/snackbox

Create the migrations directory and copy the migration files (shipped alongside the release):

sudo mkdir -p /usr/local/share/snackbox/migrations
sudo cp storage/migrations/*.sql /usr/local/share/snackbox/migrations/

3. Create the data directory

sudo mkdir -p /var/lib/snackbox/media
sudo chown -R snackbox:snackbox /var/lib/snackbox

4. Configure the environment

Create /etc/snackbox/snackbox.env with at minimum the required variables:

sudo mkdir -p /etc/snackbox
sudo tee /etc/snackbox/snackbox.env > /dev/null <<'EOF'
JWT_SECRET=<random-string-min-32-characters>
ADMIN_NAME=Admin
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=<strong-password>
EOF
sudo chmod 0640 /etc/snackbox/snackbox.env
sudo chown root:snackbox /etc/snackbox/snackbox.env

5. Install and start the systemd service

The service file is included in the repository at deployments/systemd/snackbox.service.

sudo cp deployments/systemd/snackbox.service /etc/systemd/system/snackbox.service
sudo systemctl daemon-reload
sudo systemctl enable --now snackbox

Verify it is running:

sudo systemctl status snackbox
curl http://localhost:8080/health

Kubernetes

Kubernetes support (with MariaDB and S3 media backends) is planned for 2.0.0.

Configuration Reference

All configuration is done via environment variables. The server reads an optional .env file at startup; variables already set in the environment take precedence.

Required

Variable Default Description
JWT_SECRET Secret key for signing JWT tokens. Must be at least 32 characters. No default — the server refuses to start without it.

Bootstrap (first run only)

These variables are only used when no admin user exists in the database. They are ignored on subsequent startups.

Variable Default Description
ADMIN_NAME Display name of the initial admin user
ADMIN_EMAIL Email address of the initial admin user
ADMIN_PASSWORD Password of the initial admin user

Server

Variable Default Description
LISTEN_ADDR :8080 Address and port the API server listens on
METRICS_ADDR :9091 Address and port of the Prometheus metrics endpoint. Keep this on loopback or an internal network.
READ_TIMEOUT 60s Maximum duration to read the full request
WRITE_TIMEOUT 60s Maximum duration to write the full response
IDLE_TIMEOUT 120s Maximum time to wait for the next request on a keep-alive connection
SHUTDOWN_TIMEOUT 15s Grace period for in-flight requests on shutdown

Storage

Variable Default Description
DATABASE_PATH ./storage/snackbox.db Path to the SQLite database file. Must be writable by the snackbox user. In Docker, set to /var/lib/snackbox/snackbox.db.
MIGRATIONS_PATH ./storage/migrations Directory containing SQL migration files. In Docker, set to /usr/local/share/snackbox/migrations.
STORAGE_PATH ./storage/media Directory for uploaded media files. In Docker, set to /var/lib/snackbox/media.

Security

Variable Default Description
JWT_EXPIRY 24h JWT token lifetime. Parsed with Go's time.ParseDuration (e.g. 1h, 24h, 168h).
CORS_ALLOWED_ORIGINS * Comma-separated list of allowed CORS origins, or * to allow any. For credentialed requests, list exact origins.
AUTH_RATE_LIMIT 10 Maximum login requests per second per IP address. Burst is automatically set to rate/2 + 1.
MAX_UPLOAD_SIZE 33554432 Maximum size of a single media upload in bytes (default: 32 MB).

Operations

Logs

Logs are written to stdout in plain text format.

Under Docker:

docker compose logs -f

Under systemd:

journalctl -u snackbox -f

Metrics

Snackbox exposes a Prometheus-compatible /metrics endpoint on METRICS_ADDR (default :9091). Available metrics:

Metric Type Description
snackbox_http_requests_total Counter Total HTTP requests by method, path, and status code
snackbox_http_request_duration_seconds Histogram HTTP request duration by method and path
snackbox_auth_failures_total Counter Authentication failures by reason (missing_token, invalid_token, invalid_credentials)
snackbox_media_upload_bytes_total Counter Total bytes of successfully uploaded media

Important: Do not expose the metrics port to the public internet. Restrict it to your monitoring network or bind it to loopback.

Updating

Under Docker:

docker compose pull
docker compose up -d

Under systemd:

sudo systemctl stop snackbox
sudo install -m 0755 snackbox-linux-amd64 /usr/local/bin/snackbox
sudo systemctl start snackbox

Migrations run automatically on startup. Always back up the database before updating.

Backup

Always back up both the database and the media directory together.

Under Docker, copy the files out of the container volume:

docker compose cp snackbox:/var/lib/snackbox/snackbox.db ./snackbox-backup.db
docker compose cp snackbox:/var/lib/snackbox/media ./snackbox-media-backup

Under systemd, use SQLite's hot backup:

sqlite3 /var/lib/snackbox/snackbox.db ".backup '/tmp/snackbox-backup.db'"

Also back up the media directory at STORAGE_PATH:

cp -r /var/lib/snackbox/media /tmp/snackbox-media-backup