Self-Hosting
One image. One command.
Your whole workspace.
UnDercontrol ships as a single all-in-one container — frontend and backend baked together. Run it on your own infrastructure with one command. No vendor lock-in, and nothing ever leaves your network.
# the all-in-one image: frontend + backend in one container docker run -d -p 3000:8080 \ -e HOST_DOMAIN=http://localhost:3000 \ -e JWT_SECRET=change-me-to-a-random-string \ -e LICENSE_TOKEN=eyJjcmVhdGVkX2F0IjoxNzgzNjAwMzY4LCJ2YWxpZF91bnRpbCI6MTc5MTM3NjM2OCwidGllciI6InBybyIsInVzZXJfbmFtZSI6IlNlbGYtSG9zdCBUcmlhbCIsInVzZXJfc2VjcmV0X2hhc2giOiJlZDJiYTE3OGM2NzBlYzdmZjA0NzdlZTc1MTAyNjVkM2M4NWUzN2QyNWI2NDcxNDc3OTBmZDJmZDJlMTI1YmQ4Iiwibm9uY2UiOiJiMjAzYmFkNS1mYTQ4LTQwOWMtYmU1OC0yYTc0YWJkNjNiM2YiLCJtYXhfdXNlcnMiOjV9.Nf81OrehjlpXGDP7ppap5C8GYt0eXBh5wP0y62_-mz37SHd5-3iSMmGzGZ0P4Bz9z0E1cXs1F4IwDbad2s3BAQ \ -e LICENSE_HOST_SECRET=undercontrol-selfhost-trial \ -v undercontrol-data:/app/data \ lintao0o0/undercontrol:latest
Why self-host
Your infrastructure, your rules.
Full data ownership
Tasks, notes, files, and finances live on hardware you control. Nothing is sent to a third party — not even for AI, which runs against your own provider.
No vendor lock-in
Everything-as-code. Your data is declarable in Markdown and YAML, versionable with Git, and exportable any time. No proprietary formats to escape.
Offline & air-gapped
Run inside a private network or a fully air-gapped environment. UnDercontrol keeps working without any outbound internet access.
Pick your setup
Choose your database, storage, backups, and scaling. A Raspberry Pi, a home server, a VPS, or a Kubernetes cluster — the choice is entirely yours.
Progressive deployment
Start small. Grow in place.
Start right on your own laptop with the desktop app — no Docker, no server. Graduate to a self-hosted container when you want multi-device access, then scale to PostgreSQL, cloud storage, or a full cluster. Same data model the whole way — you flip environment variables, never re-architect.
Local desktop app
Download & run. Built-in backend, fully offline. No Docker, no server.
All-in-one · SQLite
One container on your own server. Reach it from any device.
Dedicated PostgreSQL
Concurrent access and production-grade reliability.
Cloud file storage
Offload attachments to S3, R2, or MinIO.
Kubernetes cluster
High availability, autoscaling, rolling updates.
One root directory — fully portable
Everything you own lives under a single root data directory. Moving your entire workspace — from your desktop app to a self-hosted server, or from one server to another — is a single copy of ./data. No proprietary export, no re-import. Back it up, move it, restore it, done.
Free trial license
Start on Pro — on us, for 3 months.
We're in active development, so this Pro license is free for everyone to use. It's already wired into every deployment below — just paste and go.
UnDercontrol Pro — Self-Host Trial
Unlocks PostgreSQL, S3/R2 storage, multi-user with roles, and the admin dashboard.
# UnDercontrol - free 3-month Pro trial license LICENSE_TOKEN=eyJjcmVhdGVkX2F0IjoxNzgzNjAwMzY4LCJ2YWxpZF91bnRpbCI6MTc5MTM3NjM2OCwidGllciI6InBybyIsInVzZXJfbmFtZSI6IlNlbGYtSG9zdCBUcmlhbCIsInVzZXJfc2VjcmV0X2hhc2giOiJlZDJiYTE3OGM2NzBlYzdmZjA0NzdlZTc1MTAyNjVkM2M4NWUzN2QyNWI2NDcxNDc3OTBmZDJmZDJlMTI1YmQ4Iiwibm9uY2UiOiJiMjAzYmFkNS1mYTQ4LTQwOWMtYmU1OC0yYTc0YWJkNjNiM2YiLCJtYXhfdXNlcnMiOjV9.Nf81OrehjlpXGDP7ppap5C8GYt0eXBh5wP0y62_-mz37SHd5-3iSMmGzGZ0P4Bz9z0E1cXs1F4IwDbad2s3BAQ LICENSE_HOST_SECRET=undercontrol-selfhost-trial
Deployment methods
Copy a compose file, and you're running.
Every method below has the trial license baked in. The all-in-one image is the fastest path; the others are there when you want a dedicated database or a cluster.
services: undercontrol: image: lintao0o0/undercontrol:latest container_name: undercontrol ports: - "3000:8080" environment: - GIN_MODE=release - HOST_DOMAIN=http://localhost:3000 - JWT_SECRET=change-me-to-a-random-string - ADMIN_EMAIL=admin@example.com - ADMIN_PASSWORD=changeme # free 3-month Pro trial license - LICENSE_TOKEN=eyJjcmVhdGVkX2F0IjoxNzgzNjAwMzY4LCJ2YWxpZF91bnRpbCI6MTc5MTM3NjM2OCwidGllciI6InBybyIsInVzZXJfbmFtZSI6IlNlbGYtSG9zdCBUcmlhbCIsInVzZXJfc2VjcmV0X2hhc2giOiJlZDJiYTE3OGM2NzBlYzdmZjA0NzdlZTc1MTAyNjVkM2M4NWUzN2QyNWI2NDcxNDc3OTBmZDJmZDJlMTI1YmQ4Iiwibm9uY2UiOiJiMjAzYmFkNS1mYTQ4LTQwOWMtYmU1OC0yYTc0YWJkNjNiM2YiLCJtYXhfdXNlcnMiOjV9.Nf81OrehjlpXGDP7ppap5C8GYt0eXBh5wP0y62_-mz37SHd5-3iSMmGzGZ0P4Bz9z0E1cXs1F4IwDbad2s3BAQ - LICENSE_HOST_SECRET=undercontrol-selfhost-trial volumes: - ./data:/app/data restart: unless-stopped
Bring it up
Save the file, then run docker compose up -d. First boot pulls the image and runs migrations automatically.
Architecture
One image by default — split it out when you need to.
The all-in-one image serves the web app and the Go API from one container. Bring your own PostgreSQL or SQLite, and plug in an OpenAI-compatible AI provider, S3-compatible storage, or OpenTelemetry — all optional, all under your control.
Ready to own your workspace?
Paste the compose file above, or follow the full guide for PostgreSQL, S3, and Kubernetes setups.