Intro#
I have been running TREK as my self-hosted travel planner for a while now, first on v2.9.0, now on 3.0. The install is refreshingly simple. One container, no external database, just works.
If you want to know what’s new in 3.0, check out my TREK 3.0 overview post. This guide is just about getting it up and running behind nginx.
Quick Start#
Move to the directory where you want the Docker Compose file and the TREK data to live. Then just:
ENCRYPTION_KEY=$(openssl rand -hex 32) docker run -d -p 3000:3000 \
-e ENCRYPTION_KEY=$ENCRYPTION_KEY \
-v ./data:/app/data -v ./uploads:/app/uploads mauriceboe/trek
Open http://localhost:3000 and you are in. On first boot TREK seeds an admin account. If you set ADMIN_EMAIL and ADMIN_PASSWORD as environment variables, those are used, otherwise the credentials are printed to the container log (docker logs trek).
[!TIP] If you are running this on a remote server, you can already set up the nginx config before running the container the first time.
Docker Compose for Production#
For a proper setup, here is a Docker Compose file with secure defaults:
services:
app:
image: mauriceboe/trek:latest
container_name: trek
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
tmpfs:
- /tmp:noexec,nosuid,size=64m
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
- TZ=${TZ:-UTC}
- LOG_LEVEL=${LOG_LEVEL:-info}
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
Then run:
# Generate an encryption key
echo "ENCRYPTION_KEY=$(openssl rand -hex 32)" > .env
# Start the container
docker compose up -d
That is it. No database server, no Redis, no complicated setup. Just one container.
nginx Reverse Proxy#
I used pretty much the nginx config provided in the GitHub readme.
[!TIP] Don’t forget to first add the DNS entries and then run certbot for the certificates.
server {
if ($host = trek.kohnkenet.de) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name trek.kohnkenet.de;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name trek.kohnkenet.de;
# SSE/MCP endpoint - disable all buffering
location /mcp {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection '';
# Critical for SSE
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
chunked_transfer_encoding off;
}
location /ws {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
ssl_certificate /etc/letsencrypt/live/trek.kohnkenet.de/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/trek.kohnkenet.de/privkey.pem; # managed by Certbot
}
You probably noticed that I have added the MCP section to the config. This was necessary in a previous 2.9 version and I am not 100% sure if it’s still needed. But it works with it, so I kept it in.
Upgrading#
Already running an older version? Just pull and restart:
docker compose pull && docker compose up -d
Migrations run automatically on startup. No manual steps required.
When I upgraded from 2.9.0 to 3.0, I also had to swap the Docker image since it moved to mauriceboe/trek on Docker Hub. Remove the old container, pull the new image, and everything just worked. No manual migration, no database drama, nothing. My data was still there and TREK came right back up.
Quick Upgrade Checklist#
If you are coming from an older version, here is what you should check:
- Enable the Journey addon in Settings > Addons to start using the travel journal
- Update your Immich API key to include the
asset.uploadpermission (only needed if you want Journey to sync uploads to Immich) - Try Mapbox GL in Settings > Map if you want 3D terrain and a globe view (requires a free Mapbox access token)
Wrapping Up#
TREK runs in a single Docker container with SQLite, no external databases, no microservices architecture. It is one of the easiest self-hosted apps I have set up.
Huge thanks to mauriceboe and all the contributors for building this. Check out the TREK repository on GitHub and if you like the project, maybe buy the developer a coffee, they have really done an amazing job!
Happy self-hosting.
