Docker Deployment
Deploy from GHCR with Compose, port binding, and optional reverse proxy examples.
Docker Deployment
BoxBox builds into one container: Bun compiles the SvelteKit frontend, Go embeds those static files, and the runtime image starts one HTTP server on port 8080.
Prerequisites
- Docker 24+ or a recent Docker Engine.
- Docker Compose v2 if using
docker-compose.yml. - A Linux host if you want accurate system drive discovery and mount propagation.
Preferred Deployment
Deploy BoxBox with Docker Compose using the published GitHub Container Registry image. This is the recommended path for servers because it does not require cloning the repository and keeps updates simple.
Download the deployment files, edit the environment, then start the published image:
mkdir -p boxbox
cd boxbox
curl -fsSLO https://raw.githubusercontent.com/jR4dh3y/BoxBox/master/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/jR4dh3y/BoxBox/master/.env.example
mkdir -p backend
curl -fsSL https://raw.githubusercontent.com/jR4dh3y/BoxBox/master/backend/config.yaml -o backend/config.yaml
cp .env.example .env
$EDITOR .env
docker compose pull
docker compose up -d
Set these values in .env before starting:
BOXBOX_JWT_SECRET=generate-a-long-random-secret
BOXBOX_USERS_admin='$2b$12$paste-generated-hash-here'
HOST_PORT=8080
# Optional: defaults to the HOME of the user running docker compose.
# HOME_PATH=/home/your-user
# Optional: point sidebar shortcuts somewhere other than HOME_PATH/<Folder>.
# DOWNLOADS_PATH=/mnt/downloads
PUID=10001
PGID=10001
BOXBOX_IMAGE=ghcr.io/jr4dh3y/boxbox:v0.1.6@sha256:6dbc7f2b935125d534a050da2cda4a1e732660a03ba5d59eaed4bd54d1920962
Generate the password hash with htpasswd -bnBC 12 admin 'your-password' | cut -d: -f2. Keep the hash single-quoted because bcrypt hashes contain $.
Open http://localhost:8080, or use the host and port you configured with HOST_PORT.
Published Images
Release images are published to GitHub Container Registry:
docker pull ghcr.io/jr4dh3y/boxbox:v0.1.6@sha256:6dbc7f2b935125d534a050da2cda4a1e732660a03ba5d59eaed4bd54d1920962
Stable release tags update latest. Prerelease tags such as v0.2.0-rc.1 publish versioned images without moving latest, nightly builds publish to the dedicated boxbox-nightly package, and test branch images publish under branch-scoped tags in the boxbox-branch package, such as ghcr.io/jr4dh3y/boxbox-branch:branch-test-my-change.
See Release workflow for the full test-branch and stable-release process.
If you are upgrading an older deployment that still uses FM_*, filemanager, or filemanager-* names, see the v0.2.0 notes in Release workflow. The scripts/check-0.2-migration.sh helper is check-only and prints the manual changes without editing files or Docker volumes.
Optional: Reverse Proxy or Traefik
The default compose file uses normal host port binding and does not require Traefik. If you want to put BoxBox behind Traefik, remove the ports entry, attach the service to your Traefik network, and add labels for your router.
services:
boxbox:
labels:
- "traefik.enable=true"
- "traefik.http.routers.boxbox.rule=Host(`boxbox.example.test`)"
- "traefik.http.routers.boxbox.entrypoints=web"
- "traefik.http.services.boxbox.loadbalancer.server.port=8080"
networks:
- proxy
networks:
proxy:
external: true
For public or semi-public access, put TLS and access controls on your reverse proxy before exposing BoxBox beyond a trusted network.
Alternative: Simple Local Container
Use this path when you want a quick local test without Compose. It still uses the published GHCR image.
mkdir -p boxbox
cd boxbox
cat > config.yaml <<'EOF'
port: 8080
host: "0.0.0.0"
jwt_secret: "replace-this-with-a-long-random-secret"
mount_points:
- name: "home"
path: "/home/user"
read_only: false
EOF
docker pull ghcr.io/jr4dh3y/boxbox:v0.1.6@sha256:6dbc7f2b935125d534a050da2cda4a1e732660a03ba5d59eaed4bd54d1920962
docker run -d \
--name boxbox \
--user 10001:10001 \
--cap-drop ALL \
--security-opt no-new-privileges:true \
-p 8080:8080 \
-e BOXBOX_JWT_SECRET="$(openssl rand -base64 32)" \
-e BOXBOX_USERS_admin='paste-a-bcrypt-hash-here' \
-v "$PWD/config.yaml:/app/config.yaml:ro" \
-v "$HOME:/home/user" \
-v boxbox-data:/data \
-v boxbox-temp:/tmp/boxbox \
ghcr.io/jr4dh3y/boxbox:v0.1.6@sha256:6dbc7f2b935125d534a050da2cda4a1e732660a03ba5d59eaed4bd54d1920962
Open http://localhost:8080 and sign in as admin with the plaintext password used to generate the hash.
Alternative: Local Source Builds
Cloning the repository is supported, but it is not the preferred deployment method. Use this path only when you want to build the image from source instead of pulling the published GHCR image.
git clone https://github.com/jR4dh3y/BoxBox.git
cd BoxBox
docker build -t boxbox:local .
For compose, set BOXBOX_IMAGE=boxbox:local in .env, then run docker compose up -d.
Volumes
The default compose file mounts:
| Host path | Container path | Why |
|---|---|---|
./backend/config.yaml |
/app/config.yaml |
Runtime configuration. |
/media/devmon |
/media/devmon |
Auto-discovered removable drives. |
${HOME_PATH} or host $HOME |
/home/user |
User home directory browsing. |
${DESKTOP_PATH} or $HOME/Desktop |
/home/user/Desktop |
Desktop sidebar shortcut. |
${DOWNLOADS_PATH} or $HOME/Downloads |
/home/user/Downloads |
Downloads sidebar shortcut. |
${DOCUMENTS_PATH} or $HOME/Documents |
/home/user/Documents |
Documents sidebar shortcut. |
${MUSIC_PATH} or $HOME/Music |
/home/user/Music |
Music sidebar shortcut. |
${PICTURES_PATH} or $HOME/Pictures |
/home/user/Pictures |
Pictures sidebar shortcut. |
${VIDEOS_PATH} or $HOME/Videos |
/home/user/Videos |
Videos sidebar shortcut. |
boxbox-temp |
/tmp/boxbox |
Chunked upload assembly. |
boxbox-data |
/data |
Persistent app data, including custom drive names. |
Use :ro on a volume or read_only: true in config.yaml when a path should never be modified through BoxBox.
The sidebar's default folders are configured as normal mount points named desktop, downloads, documents, music, pictures, and videos. To remap one shortcut, set the matching host path in .env and restart, for example DOWNLOADS_PATH=/srv/incoming. Do not use ~ in .env; use an absolute path like /home/alex/Downloads.
Mount Propagation
The compose file uses rslave for host mount paths so new host mounts can appear inside the container. This matters for removable drives and some NAS/rclone mounts.
volumes:
- /media/devmon:/media/devmon:rslave
Updating
docker compose pull
docker compose up -d
For v0.2.0, old FM_* environment variables still work as deprecated aliases, but rename them to BOXBOX_*. BOXBOX_* values take precedence when both are set.
For local source builds:
git pull
docker build --no-cache -t boxbox:local .
docker compose up -d
For a docker run deployment:
docker pull ghcr.io/jr4dh3y/boxbox:v0.1.6@sha256:6dbc7f2b935125d534a050da2cda4a1e732660a03ba5d59eaed4bd54d1920962
docker stop boxbox
docker rm boxbox
# Re-run the docker run command with the same volumes and env values.
Health and Logs
curl http://localhost:8080/health
docker compose ps
docker compose logs -f boxbox
The health response is:
{"status":"ok"}
Permission Notes
The container runs as UID/GID 10001:10001 by default and drops all Linux capabilities. Set PUID/PGID before first start if your mounted files use another identity. BoxBox does not chown host paths or existing named volumes; grant that identity only the host permissions it needs.