How to Self-Host a Helpdesk with FreeScout (A Shared Inbox That Turns Emails into Tickets)

A support@ mailbox read in Outlook works until two people answer the same email, or one falls through. FreeScout is a lightweight helpdesk in the style of Help Scout: it pulls the mailbox over IMAP, every thread becomes a conversation with a status (active, pending, closed), an assignee, tags and private notes, replies go out through SMTP as if from the mailbox, saved replies cover the common questions, and reports show who answered what. PHP and MySQL, small, and the modules add a knowledge base, time tracking, SLAs and a customer portal.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/freescout/compose.yaml (app + MariaDB) |
| Web | https://help.example.com |
| Needs | a mailbox with IMAP + SMTP (Gmail app password, or your domain's mailbox) |
| Mailbox | Manage → Mailboxes → New: incoming IMAP, outgoing SMTP, fetch every minute |
| Agents | Manage → Users; roles admin/user; per-mailbox access |
| Modules | Manage → Modules: Knowledge Base, Time Tracking, SLA, Tags, Custom Fields… |
1. The compose file
mkdir -p ~/docker/freescout/{data,config} && cd ~/docker/freescout
nano compose.yaml
services:
freescout:
image: tiredofit/freescout:latest
container_name: freescout
ports:
- "127.0.0.1:8096:80"
environment:
SITE_URL: https://help.example.com
ADMIN_EMAIL: you@example.com
ADMIN_PASS: ${ADMIN_PASS}
ADMIN_FIRST_NAME: John
ADMIN_LAST_NAME: Smith
DB_HOST: freescout-db
DB_NAME: freescout
DB_USER: freescout
DB_PASS: ${DB_PASSWORD}
TIMEZONE: Europe/London
ENABLE_SSL_PROXY: "TRUE"
DISPLAY_ERRORS: "FALSE"
volumes:
- ./data:/data
- ./config:/www/html/storage/app/public
depends_on: [freescout-db]
restart: unless-stopped
freescout-db:
image: mariadb:11
container_name: freescout-db
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MARIADB_DATABASE: freescout
MARIADB_USER: freescout
MARIADB_PASSWORD: ${DB_PASSWORD}
volumes:
- ./db:/var/lib/mysql
restart: unless-stopped
docker compose up -d
(Note: port 8096 clashes with Jellyfin if you used it; pick another.)
2. Proxy and login
help.example.com → the mapped port (28), HTTPS; SITE_URL must match. Log in with the admin email/password from the environment.
3. Connect the support mailbox
Manage → Mailboxes → New Mailbox: name "Support", email support@example.com. Connection settings → Fetching emails: IMAP host, port 993, SSL, the mailbox login (an app password for Gmail/Outlook.com; a real mailbox on your domain — Mailcow (138) or your host — is cleaner). Sending emails: SMTP host, 587, TLS. Check connection for both. Then Fetch runs every minute via the container's cron; existing mail appears as conversations.
Send a test from another address; it shows up in the Support inbox within a minute.
4. Work the inbox
Each conversation: the thread, a Status (Active → Pending while waiting on the customer → Closed), an Assignee, Tags ("repair", "invoice query"), a Note (yellow, internal — "customer was rude on the phone, be patient") that the customer never sees. Reply sends through SMTP from support@ with the agent's name in the signature. Saved Replies for "how to find your Windows version", "our hours", "send the serial number" — one click, editable before sending. Snooze a conversation to Monday; Follow one you're not assigned to.
Customers build automatically: every address becomes a profile with its full history — the person who emailed three times about the same laptop is visible as one record.
5. Agents and reports
Manage → Users: each person with access to specific mailboxes; Email Notifications per user (new conversation, assigned to me, customer replied); the Alerts for unanswered conversations. Reports (module): response times, volume by day, by agent, by tag — the "how busy are we" chart.
6. Modules worth adding
Manage → Modules: the free ones — Tags, Saved Replies (built in), Custom Fields (device model, job number), Workflows (auto-assign, auto-tag by keyword, auto-close after 7 days pending), Knowledge Base (public help articles at help.example.com/kb that reduce the emails), Time Tracking (bill hourly work, 188), Customer Portal, SLA, Satisfaction Ratings. Many are paid one-off licences for the author's work — cheap compared with a seat fee.
7. Back up
./db (dump, 65), ./data, ./config (attachments) and .env nightly. The mailbox itself still exists on the mail server, so FreeScout's copy is the working view, not the only one.
Troubleshooting
Fetch fails: "IMAP connection error". App password required (Gmail 2FA), IMAP enabled on the account, port/SSL correct; the container's log names the step.
Replies go out from the agent's name but wrong address. Mailbox → Sending → From name/address settings; aliases under the mailbox.
Attachments broken after proxy change. SITE_URL and ENABLE_SSL_PROXY.
Emails fetched twice / loops with an autoresponder. Workflows to skip auto-replies; disable the mailbox's own auto-reply.
Wrapping up
Two containers, a mailbox over IMAP/SMTP, agents with mailbox access, saved replies and notes. support@ stops being a shared Outlook folder and becomes a queue with owners, statuses and history — and the knowledge base module answers the question before it's asked.
