Why self-host a project manager
Linear, Asana, Monday.com — SaaS project management tools charge per seat and raise prices regularly. TREK flips the model: you host the app on your own VPS, your data never leaves your infrastructure, and the monthly cost is the VPS, not the seats.
With 14 k+ GitHub stars and an AGPL-3.0 licence, TREK is an active community project. Version 4.3.3 is stable, Docker-native, and requires no external database: SQLite is embedded in the image.
What you get with self-hosted TREK
- Unlimited Kanban boards — create as many projects and columns as needed, no seat limit.
- Milestones and sprints — plan by cycle, visualise progress in the team dashboard.
- Team management — invite members by email, assign roles (Admin, Member, Viewer) per project.
- REST API — integrate CI/CD pipelines to create issues or update statuses automatically.
- OIDC / SSO — connect Authentik, Pocket ID or Keycloak for centralised login.
- File attachments — upload files and screenshots directly onto issues.
- Embedded SQLite — no external database, back up everything with one command.
Prerequisites
You need a Ubuntu 24.04 VPS with at least 1 GB RAM and 1 GB disk space (more depending on your attachments). Docker and the Compose plugin must be installed:
curl -fsSL https://get.docker.com | shNo domain name is required for the initial installation — TREK is accessible via an SSH tunnel.
Installing TREK
Create the directory and Compose file
On the server, create a dedicated directory:
mkdir -p /opt/trek && cd /opt/trekCreate
/opt/trek/docker-compose.yml:services: trek: image: mauriceboe/trek:4.3.3 restart: unless-stopped ports: - "127.0.0.1:3000:3000" environment: NODE_ENV: production ENCRYPTION_KEY: "replace-with-a-random-32-char-string" ADMIN_EMAIL: [email protected] ADMIN_PASSWORD: "StrongAdminPass42!" TRUST_PROXY: "1" volumes: - trek-data:/app/data - trek-uploads:/app/uploads volumes: trek-data: {} trek-uploads: {}⚠️ In production, replace
ENCRYPTION_KEYwith a random 32+ character string and choose a strong admin password.Start TREK
Launch the container:
docker compose up -dTREK downloads the image (~462 MB), initialises SQLite and starts Node.js. Drizzle ORM migrations run on the first launch. Wait 30–45 seconds before accessing the interface.
Check startup:
docker compose logs -f trekLook for
Server listening on port 3000— that's the signal TREK is ready.Access the interface
Open an SSH tunnel from your local machine:
ssh -L 3000:127.0.0.1:3000 root@<your-vps-ip>Then open
http://localhost:3000in your browser. The TREK login page appears. Sign in with[email protected]and the password set inADMIN_PASSWORD.Create your first project
After logging in:
1. Click New Workspace → give it a name.
2. Click New Project → choose the Kanban template.
3. Add your first issue to the To Do column.You're ready to go. Invite collaborators from Settings → Members.
Configure a domain and nginx
To access TREK from any device without an SSH tunnel, attach a domain and configure nginx as a reverse proxy. Here is an example nginx server block for HTTPS:
server {
listen 443 ssl;
server_name trek.your-domain.com;
location / {
proxy_pass http://127.0.0.1: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;
# WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Then add APP_URL: https://trek.your-domain.com to the TREK service environment variables so that invitation links and OIDC notifications use the correct URL.
Backup and maintenance
TREK stores data in two Docker volumes: trek-data (SQLite database) and trek-uploads (file attachments). Back up both:
# Database
docker run --rm -v trek_trek-data:/data -v /backup:/backup alpine \
tar czf /backup/trek-data-$(date +%Y%m%d).tar.gz -C /data .
# Uploads
docker run --rm -v trek_trek-uploads:/data -v /backup:/backup alpine \
tar czf /backup/trek-uploads-$(date +%Y%m%d).tar.gz -C /data .To update TREK to a new version, update the image tag in docker-compose.yml, then:
docker compose pull && docker compose up -dSQLite migrations apply automatically on startup.