How to Self-Host LibreDesk with Docker Compose
What Is LibreDesk?
LibreDesk started as a modern rethink of the open-source helpdesk space in early 2026 and has already reached v1.0. Built by the team behind Listmonk at Zerodha Tech, LibreDesk is a single-binary Go application with a Vue.js frontend that handles shared inboxes, SLA tracking, automation rules, CSAT surveys, and role-based access control. It connects email via IMAP/SMTP, Google OAuth, or Microsoft OAuth — and includes AI-assisted response rewriting out of the box.
Unlike older PHP-based helpdesks, LibreDesk compiles to a single binary with minimal dependencies: PostgreSQL and Redis. The result is fast startup, low memory usage, and straightforward upgrades.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 1 GB of RAM (512 MB minimum)
- 5 GB of free disk space
- A domain name (recommended for email integration)
Docker Compose Configuration
Create a directory for LibreDesk and add a docker-compose.yml:
services:
app:
image: libredesk/libredesk:v1.0.3
restart: unless-stopped
ports:
- "9000:9000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./uploads:/libredesk/uploads # User-uploaded attachments
- ./config.toml:/libredesk/config.toml # Application config
environment:
- LIBREDESK_SYSTEM_USER_PASSWORD=changeme_admin_password # Change this
command: >
sh -c "./libredesk --install --idempotent-install --yes --config /libredesk/config.toml &&
./libredesk --upgrade --yes --config /libredesk/config.toml &&
./libredesk --config /libredesk/config.toml"
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_USER: libredesk
POSTGRES_PASSWORD: changeme_db_password # Change this
POSTGRES_DB: libredesk
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432" # Localhost only for security
healthcheck:
test: ["CMD-SHELL", "pg_isready -U libredesk"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
ports:
- "127.0.0.1:6379:6379" # Localhost only for security
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres-data:
redis-data:
Create a config.toml file alongside the compose file:
[app]
log_level = "info"
env = "production"
check_updates = true
# Generate a 32-character encryption key: openssl rand -hex 16
encryption_key = "changeme_32_char_encryption_key!"
[app.server]
address = "0.0.0.0:9000"
disable_secure_cookies = true # Set to false when using HTTPS via reverse proxy
read_timeout = "10s"
write_timeout = "10s"
max_body_size = 104857600 # 100 MB max upload
keepalive_timeout = "10s"
[upload]
provider = "fs"
[upload.fs]
upload_path = "uploads"
[db]
host = "db"
port = 5432
user = "libredesk"
password = "changeme_db_password" # Must match POSTGRES_PASSWORD above
database = "libredesk"
ssl_mode = "disable"
max_open = 25
max_idle = 25
max_lifetime = "300s"
[redis]
address = "redis:6379"
user = ""
password = ""
db = 0
Generate the encryption key and update passwords before starting:
# Generate encryption key (32 characters)
openssl rand -hex 16
# Start the stack
docker compose up -d
Initial Setup
- Wait for all containers to start — the app runs database migrations automatically on first boot
- Open
http://your-server-ip:9000in your browser - Log in with username System and the password you set in
LIBREDESK_SYSTEM_USER_PASSWORD - Navigate to Settings → Inboxes to connect your first email inbox (IMAP/SMTP, Google OAuth, or Microsoft OAuth)
- Create agent accounts under Settings → Agents
- Configure teams and roles under Settings → Teams
If you didn’t set LIBREDESK_SYSTEM_USER_PASSWORD, set it manually:
docker exec -it libredesk-app-1 ./libredesk --set-system-user-password
Configuration
Key Features
| Feature | Description |
|---|---|
| Shared inboxes | Multiple email inboxes with team routing |
| SLA management | Define response and resolution time targets |
| Automation rules | Trigger actions based on ticket conditions |
| CSAT surveys | Customer satisfaction surveys after resolution |
| Macros | Pre-built response templates (canned replies) |
| Auto-assignment | Round-robin and load-balanced ticket assignment |
| Custom attributes | Add custom fields to conversations |
| AI assist | Rewrite, expand, or polish agent responses |
| Webhooks | HTTP callbacks on conversation events |
| Activity logs | Audit trail for all actions |
| Command bar | Quick navigation with Ctrl+K |
| Role-based access | Granular permissions per role |
Email Inbox Setup
LibreDesk supports three methods for connecting email:
- Google OAuth — Recommended for Gmail/Google Workspace. Configure in Settings → Inboxes → Add Inbox → Google
- Microsoft OAuth — For Outlook/Microsoft 365. Configure in Settings → Inboxes → Add Inbox → Microsoft
- Manual IMAP/SMTP — For any email provider. Enter IMAP server, port, credentials, and SMTP details
S3 Storage
For production deployments with many attachments, switch to S3-compatible storage:
[upload]
provider = "s3"
[upload.s3]
endpoint = "https://s3.example.com"
access_key = "your-access-key"
secret_key = "your-secret-key"
region = "us-east-1"
bucket = "libredesk-uploads"
Advanced Configuration
OpenID Connect SSO
LibreDesk supports OIDC providers for single sign-on. Configure through the admin UI under Settings → Authentication. Compatible with Keycloak, Authentik, and other OIDC-compliant identity providers.
Environment Variable Overrides
Any config.toml setting can be overridden via environment variables using the LIBREDESK_ prefix with double underscores for nesting:
environment:
LIBREDESK_DB__HOST: "custom-db-host"
LIBREDESK_APP__LOG_LEVEL: "debug"
LIBREDESK_REDIS__ADDRESS: "custom-redis:6379"
Reverse Proxy
LibreDesk uses WebSockets for real-time updates. Your reverse proxy must pass WebSocket upgrade headers. With Nginx Proxy Manager, point to port 9000 and enable WebSocket support.
Nginx configuration snippet:
location / {
proxy_pass http://localhost:9000;
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;
client_max_body_size 100M;
}
Once HTTPS is active via reverse proxy, set disable_secure_cookies = false in config.toml and restart.
For general reverse proxy setup, see our Reverse Proxy guide.
Backup
Back up the PostgreSQL database and the uploads directory:
# Database backup
docker compose exec db pg_dump -U libredesk libredesk > libredesk_backup.sql
# Uploads backup (if using filesystem storage)
tar czf libredesk-uploads.tar.gz uploads/
Always back up config.toml as well — it contains your encryption key.
For a comprehensive backup strategy, see our Backup guide.
Troubleshooting
WebSocket Connection Errors
Symptom: Real-time updates don’t work. Console shows WebSocket connection failures.
Fix: Ensure your reverse proxy passes WebSocket upgrade headers. Check that proxy_http_version 1.1 and the Upgrade/Connection headers are set in your Nginx config.
System User Password Not Working
Symptom: Cannot log in with the System account after first boot.
Fix: The LIBREDESK_SYSTEM_USER_PASSWORD env var only applies on first run. Reset it manually:
docker exec -it libredesk-app-1 ./libredesk --set-system-user-password
Emails Not Being Fetched
Symptom: Inbox is connected but no emails appear.
Fix: Check the app logs for IMAP connection errors:
docker compose logs app | grep -i "imap\|mail\|inbox"
Verify your IMAP server allows app-specific passwords or OAuth tokens. Gmail requires an App Password if 2FA is enabled, unless you use Google OAuth.
Container Fails to Start
Symptom: The app container exits immediately.
Fix: Check that config.toml has all required fields, especially encryption_key (must be exactly 32 characters). Verify PostgreSQL and Redis are healthy:
docker compose ps
docker compose logs app
Resource Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 256 MB (app only) | 512 MB-1 GB (with PostgreSQL + Redis) |
| CPU | 1 core | 2 cores |
| Disk | 2 GB | 5-10 GB (scales with attachments) |
LibreDesk is a single Go binary — it starts in seconds and uses minimal resources compared to Ruby or Java-based helpdesks.
Verdict
If you need a modern helpdesk that runs lean, LibreDesk is the most promising newcomer in the self-hosted space. The Go single-binary architecture means fast startup, simple upgrades, and low resource usage. Features like SLA management, automation rules, and CSAT surveys put it on par with tools that have been around for years.
The catch: v1.0 shipped in January 2026. The feature set is solid but the ecosystem is young — no marketplace, limited integrations, and a small community. For teams that need proven stability and dozens of integrations, Zammad or FreeScout are safer bets today. For teams willing to adopt early and contribute feedback, LibreDesk is worth watching closely.
FAQ
How does LibreDesk compare to FreeScout?
LibreDesk is newer (v1.0 in 2026) with a modern Vue.js UI, built-in SLA management, and Go’s performance. FreeScout is more mature with a larger module ecosystem but is PHP/Laravel-based and requires paid modules for features LibreDesk includes free.
Does LibreDesk support multiple inboxes?
Yes. You can connect multiple email inboxes and route them to different teams. Each inbox can use a different email provider.
Can I use LibreDesk for internal IT ticketing?
Yes, though it’s optimized for customer-facing support with email-based workflows. For internal IT service management with ITIL compliance, consider OTOBO instead.
Is LibreDesk production-ready?
Version 1.0 is stable and actively maintained. The Zerodha Tech team (behind Listmonk) has a track record of shipping reliable open-source software. Evaluate whether the current feature set meets your needs.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments