How to Configure TREK with Docker Compose for Production: A Complete Security Guide
TREK provides a production-hardened docker-compose.yml that enables read-only root filesystems, drops Linux capabilities, and requires only a .env file and two bind-mounted volumes to run securely behind a reverse proxy.
The mauriceboe/TREK repository ships with a security-first Docker Compose configuration designed specifically for production workloads. When you configure TREK with Docker Compose for production, you leverage a hardened service definition that implements defense-in-depth principles without requiring manual security tuning.
Security Hardening in the Production Compose File
The docker-compose.yml in the repository root applies several Linux security mechanisms by default. These settings create a minimal attack surface by restricting what the containerized Node.js process can access or execute.
Read-Only Root Filesystem
The app service mounts the container filesystem as read-only using read_only: true. This prevents runtime modifications to application code or system binaries. To accommodate necessary write operations, the configuration mounts a tmpfs volume at /tmp with specific security flags:
tmpfs: /tmp:noexec,nosuid,size=64m
This provides a writable, in-memory temporary directory that prohibits execution (noexec) and set-user-ID operations (nosuid), as defined in docker-compose.yml lines 5 and 14.
Linux Capability Restrictions
The container drops all Linux capabilities via cap_drop: [ALL] and selectively re-adds only the minimum required set:
- CHOWN: Required to change file ownership during entrypoint initialization
- SETUID and SETGID: Required to drop privileges from root to the
nodeuser
Additionally, security_opt: no-new-privileges:true prevents the process from gaining extra privileges through setuid or setgid binaries. These settings appear in docker-compose.yml lines 6, 8, and 10.
Volume Configuration for Data Persistence
TREK requires two persistent storage locations that survive container restarts. The compose file uses bind mounts by default, mapping host directories to container paths:
./data→/app/data: Stores the SQLite database, application logs, and generated encryption key files./uploads→/app/uploads: Holds user-uploaded media files
These mappings are documented in wiki/Install-Docker-Compose.md line 21. If you prefer Docker-managed named volumes over bind mounts, replace the host paths with volume names:
volumes:
- trek_data:/app/data
- trek_uploads:/app/uploads
Then declare the volumes at the compose file level:
volumes:
trek_data:
trek_uploads:
Required Environment Variables
All runtime configuration flows through environment variables loaded from a .env file placed alongside docker-compose.yml. The container refuses to start without specific variables defined.
Core Configuration
At minimum, set these four variables:
| Variable | Purpose | Example |
|---|---|---|
ENCRYPTION_KEY |
32-byte hex string for at-rest data encryption | openssl rand -hex 32 |
TZ |
Local timezone for scheduled tasks and logs | Europe/Berlin |
ALLOWED_ORIGINS |
CORS whitelist for browser requests | https://trek.example.com |
APP_URL |
Canonical URL for email links and redirects | https://trek.example.com |
The ENCRYPTION_KEY persists automatically to data/.encryption_key after the first start. These variables are fully documented in wiki/Environment-Variables.md.
HTTPS and Security Flags
When running behind a TLS-terminating reverse proxy, enable additional security headers:
FORCE_HTTPS=true
TRUST_PROXY=1
Setting FORCE_HTTPS=true enforces HTTPS redirects, HSTS headers, Content Security Policy upgrades, and secure cookies. The TRUST_PROXY=1 variable tells the Express.js server to trust the first proxy hop, preventing redirect loops. You may also explicitly set COOKIE_SECURE=true, though this auto-enables when FORCE_HTTPS is active.
Reverse Proxy and TLS Termination
The TREK compose configuration assumes TLS termination occurs at a reverse proxy (nginx, Caddy, or Traefik). The container exposes port 3000 for upstream communication. When configuring your proxy, ensure you forward the protocol and client IP information:
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
}
Complete nginx and Caddy examples appear in wiki/Reverse-Proxy.md. Remember to set TRUST_PROXY=1 when using this configuration to prevent Express from treating the proxy as an untrusted client.
Image Tagging Strategy
The default docker-compose.yml references mauriceboe/trek:dev for development. For production, pin to a stable version to prevent accidental major updates:
# Track the latest 3.x release
image: mauriceboe/trek:3
# Or pin to a specific patch version
image: mauriceboe/trek:3.0.15
This strategy ensures reproducible deployments and controlled upgrade paths, as detailed in wiki/Install-Docker-Compose.md line 61.
Deployment Commands
First, create the .env file:
cat > .env << 'EOF'
ENCRYPTION_KEY=$(openssl rand -hex 32)
TZ=Europe/Berlin
ALLOWED_ORIGINS=https://trek.example.com
APP_URL=https://trek.example.com
FORCE_HTTPS=true
TRUST_PROXY=1
EOF
Start the application:
docker compose up -d
docker compose logs -f
Upgrade to a newer version:
docker compose pull
docker compose up -d --force-recreate
The restart: unless-stopped policy in docker-compose.yml line 51 ensures the container automatically restarts after host reboots or unexpected failures.
Summary
- TREK's
docker-compose.ymlimplements production security defaults including read-only filesystems, dropped capabilities, and no-new-privileges restrictions. - Two volumes (
./dataand./uploads) persist SQLite databases and user media across container restarts, configurable as bind mounts or named volumes. - Four environment variables (
ENCRYPTION_KEY,TZ,ALLOWED_ORIGINS,APP_URL) are required to start, withFORCE_HTTPSandTRUST_PROXYnecessary for reverse proxy deployments. - Reverse proxy configuration must include
X-Forwarded-Protoheaders and setTRUST_PROXY=1to avoid redirect loops. - Pin image tags to major versions (e.g.,
mauriceboe/trek:3) rather than usinglatestordevtags in production.
Frequently Asked Questions
Does TREK require root privileges to run in Docker?
No. While the container starts as root to perform initial permission setup, the entrypoint script drops privileges to the node user before starting the application. The cap_add settings in docker-compose.yml provide only the specific capabilities needed for this privilege drop (CHOWN, SETUID, SETGID), and no-new-privileges:true prevents privilege escalation.
Can I use PostgreSQL or MySQL instead of SQLite?
The provided docker-compose.yml configures TREK for SQLite via the ./data volume mount. To use PostgreSQL or MySQL, you would need to modify the environment variables to include database connection strings (see wiki/Environment-Variables.md) and add a database service to your compose file, though the official production configuration optimizes for the zero-config SQLite setup.
How do I backup TREK data when using Docker Compose?
Backup the ./data directory, which contains the SQLite database (trek.db), application logs, and the .encryption_key file. If using named volumes instead of bind mounts, use docker run --rm -v trek_data:/data -v $(pwd):/backup alpine tar czf /backup/trek-backup.tar.gz -C /data . to create a compressed archive.
What happens if I don't set FORCE_HTTPS behind a reverse proxy?
Without FORCE_HTTPS, TREK will not redirect HTTP traffic to HTTPS, won't set the Secure flag on cookies, and won't send HSTS headers. However, if your reverse proxy terminates TLS but doesn't properly set X-Forwarded-Proto, leaving FORCE_HTTPS disabled prevents infinite redirect loops while you configure the proxy headers correctly.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →