Getting Started
Deploy Open Help Desk with Docker Compose in under five minutes.
Open Help Desk is distributed as a single Go binary with the React frontend embedded — there is nothing to install or serve beyond the binary and a PostgreSQL database. The Docker Compose stack in docker/ sets both up with a single command.
Architecture overview
- Binary — a single Go executable that serves the REST API at
/api/, the MCP server at/mcp/, and the React SPA at/. - Frontend — compiled at build time and embedded in the binary via
go:embed. No Node.js in production. - Database — PostgreSQL. Schema migrations run automatically on every startup before accepting traffic.
- Plugins — WASM modules sandboxed via wazero, loaded from
ATTACHMENT_DIR/../plugins/.
Quick start
Requirements: Docker Engine 24+ and Docker Compose V2.
Clone the repository
git clone https://github.com/PubliciaLLC/open-help-desk
cd open-help-desk/docker
Create your environment file
cp .env.example .env
Open .env and set the three required values. Generate secure secrets with openssl rand -base64 32.
BASE_URL=http://localhost:8080
SESSION_SECRET=<at-least-32-random-chars>
JWT_SECRET=<different-32-random-chars>
Start the stack
docker compose up -d
Docker pulls the images, builds the application (Go + React), and starts PostgreSQL. Migrations run automatically before the app begins serving traffic. Wait for:
open-help-desk | open-help-desk listening on :8080
Open the app and complete setup
Navigate to http://localhost:8080. On a fresh database the app redirects to /setup, where you enter a name, email address, and password to create the first admin account. The setup page is permanently disabled once any user exists — it cannot be reached again.
Data persistence — Postgres data is stored in docker/data/postgres/ and file attachments in docker/data/attachments/. Both directories are gitignored and survive container restarts and rebuilds.
Verify the installation
curl http://localhost:8080/health
# → {"status":"ok"}
Configuration reference
All configuration is read from environment variables at startup. Variables marked required cause the server to exit with an error if unset or empty.
Required
| Variable | Type | Description |
|---|---|---|
DATABASE_URL | string | Full PostgreSQL DSN. Example: postgres://user:pass@host:5432/db?sslmode=disable |
BASE_URL | string | Public-facing URL of the app, no trailing slash. Used in email notification links and SAML SP metadata. Example: https://helpdesk.example.com |
SESSION_SECRET | string | Secret used to sign and verify session cookies. Must be at least 32 characters. Rotating this value invalidates all active user sessions. |
JWT_SECRET | string | Secret used to sign JWTs for the OAuth2 token endpoint and API bearer tokens. Must be at least 32 characters. |
Server
| Variable | Default | Description |
|---|---|---|
HTTP_PORT | 8080 | TCP port the HTTP server listens on. Change this when running behind a reverse proxy that handles TLS. |
ATTACHMENT_DIR | /data/attachments | Filesystem path where uploaded files are stored. The directory and its parents are created on startup if they don't exist. Must be writable by the application user (ohd in Docker). |
APP_ENV | production | Set to development to enable verbose request logging, relaxed CORS, and friendlier error messages in API responses. |
Email (SMTP)
Email notifications are silently disabled when SMTP_HOST is not set. No restart is needed to toggle email; the app checks this value at startup.
| Variable | Default | Description |
|---|---|---|
SMTP_HOST | — | Hostname of the SMTP server. Examples: smtp.sendgrid.net, email-smtp.us-east-1.amazonaws.com |
SMTP_PORT | 587 | SMTP port. 587 for STARTTLS (recommended), 465 for implicit TLS (SMTPS), 25 for plain/relay. |
SMTP_USER | — | SMTP username for authentication. |
SMTP_PASSWORD | — | SMTP password. Use a secret manager or Docker secret in production — avoid committing this to .env. |
SMTP_FROM | — | The From address for all outbound email. Example: Open Help Desk <helpdesk@example.com> |
SAML 2.0
| Variable | Default | Description |
|---|---|---|
SAML_ENABLED | false | Enable SAML 2.0 SSO. When true, local auth is disabled for non-admin users. |
SAML_METADATA_URL | — | URL to your Identity Provider's SAML metadata XML document. Required when SAML_ENABLED=true. |
SAML_CERT_FILE | — | Container path to the SP certificate PEM file. Required when SAML is enabled. |
SAML_KEY_FILE | — | Container path to the SP private key PEM file. Required when SAML is enabled. |
Feature flags
| Variable | Default | Description |
|---|---|---|
MFA_ENABLED | false | Enable TOTP MFA enrollment for all users. Admins can additionally enforce MFA per-role from the settings panel. |
SLA_ENABLED | false | Enable SLA policy tracking. When false, no SLA-related UI or data is shown. |
GUEST_SUBMISSION_ENABLED | false | Allow unauthenticated ticket submission. Guests receive a tracking number and email link for their specific ticket. |
First-run setup
After completing the /setup wizard and creating your admin account, work through this checklist before inviting users:
- Create your CTI hierarchy — go to Admin → Categories and define at least one Category. Without a Category, no ticket can be created. See the Admin Guide: Categories for a worked example.
- Review ticket statuses — the system creates five default statuses (New, In Progress, Pending, Resolved, Closed). If you need intermediate statuses (e.g. "Awaiting Vendor"), add them now under Admin → Statuses. See Admin Guide: Statuses.
- Create groups and assign scope — define which staff teams handle which categories. See Admin Guide: Groups & scope.
- Create or invite staff accounts — create staff accounts from Admin → Users, or have staff register themselves and then promote their role. See Admin Guide: Users & roles.
- Configure email (optional) — set the SMTP environment variables and restart. Preview and customize templates under Admin → Email. See Admin Guide: Email templates.
-
Configure SLA policies (optional, requires
SLA_ENABLED=true) — set response and resolution targets per priority or category under Admin → SLA. See Admin Guide: SLA policies. - Set up SSO (optional) — configure SAML environment variables and restart. See Authentication: SAML 2.0.
- Install plugins (optional) — upload or point to WASM plugin files from Admin → Plugins. See Admin Guide: Installing plugins.
Upgrading
cd open-help-desk
git pull
cd docker
docker compose up -d --build
The application runs database migrations automatically on startup, before it begins accepting traffic. There is no manual migration step. If a migration fails (e.g. due to a conflict with manual schema changes), the server exits with an error message — check the container logs.
Back up your database before upgrading in production. Migrations are forward-only; there is no automatic rollback if you need to downgrade.
Zero-downtime upgrades
For production deployments where downtime is unacceptable, the recommended approach is:
- Take a database backup.
- Pull the new image.
- Start a second container with the new image pointing to the same database. Migrations run and complete.
- Shift traffic to the new container.
- Stop the old container.
This works because migrations are idempotent — running them on an already-migrated database is a no-op.