← All articles
a computer sitting on top of a wooden desk

Zammad: Self-Hosted Helpdesk and Ticketing System

Productivity 2026-02-14 · 7 min read helpdesk ticketing customer-support self-hosted
By Selfhosted Guides Editorial TeamSelf-hosting practitioners covering open source software, home lab infrastructure, and data sovereignty.

Every growing team hits the point where support requests outgrow a shared inbox. Emails get missed, nobody knows who's handling what, and customers wait days for responses that should take hours. A helpdesk system fixes this by turning unstructured communication into trackable, assignable, prioritizable tickets.

Photo by Tomas Martinez on Unsplash

Zammad is an open source helpdesk and ticketing system that handles email, chat, phone, social media, and web forms in a single interface. It's built with Ruby on Rails and ships with a polished web UI, a knowledge base, SLA management, and reporting. Think of it as a self-hosted alternative to Zendesk or Freshdesk, without the per-agent pricing that makes commercial helpdesks expensive as your team scales.

Zammad helpdesk dashboard showing ticket queue and agent overview

Why Zammad?

The helpdesk space has plenty of options, both hosted and self-hosted. Zammad stands out for several reasons:

The trade-off compared to simpler tools like osTicket: Zammad requires more resources (Elasticsearch, PostgreSQL, Redis) and has a heavier footprint. But the UI quality and feature set justify the overhead for teams that rely on their helpdesk daily.

Architecture

Zammad runs several interconnected services:

  1. Rails application -- The core web application and API server
  2. WebSocket server -- Powers real-time updates in the browser (new tickets, live chat)
  3. Background workers -- Process emails, run triggers, send notifications
  4. PostgreSQL -- Primary data store for tickets, users, and configuration
  5. Elasticsearch -- Full-text search index for fast ticket and knowledge base search
  6. Redis -- Session storage and caching
  7. Memcached -- Additional caching layer

This is not a lightweight application. Plan for at least 4 GB of RAM, ideally 8 GB for production use with Elasticsearch.

Docker Deployment

Zammad provides official Docker Compose files that orchestrate all the required services.

Prerequisites

Docker Compose Setup

# docker-compose.yml
services:
  zammad-railsserver:
    image: ghcr.io/zammad/zammad:latest
    container_name: zammad-railsserver
    command: ["zammad-railsserver"]
    depends_on:
      - zammad-memcached
      - zammad-postgresql
      - zammad-redis
    volumes:
      - zammad-storage:/opt/zammad/storage
    environment: &zammad-env
      POSTGRESQL_HOST: zammad-postgresql
      POSTGRESQL_USER: zammad
      POSTGRESQL_PASS: zammad
      POSTGRESQL_DB: zammad_production
      MEMCACHE_SERVERS: zammad-memcached:11211
      REDIS_URL: redis://zammad-redis:6379
      ELASTICSEARCH_HOST: zammad-elasticsearch
      RAILS_TRUSTED_PROXIES: "['127.0.0.1', '::1']"
    restart: unless-stopped

  zammad-websocket:
    image: ghcr.io/zammad/zammad:latest
    container_name: zammad-websocket
    command: ["zammad-websocket"]
    depends_on:
      - zammad-railsserver
    environment:
      <<: *zammad-env
    restart: unless-stopped

  zammad-worker:
    image: ghcr.io/zammad/zammad:latest
    container_name: zammad-worker
    command: ["zammad-worker"]
    depends_on:
      - zammad-railsserver
    volumes:
      - zammad-storage:/opt/zammad/storage
    environment:
      <<: *zammad-env
    restart: unless-stopped

  zammad-nginx:
    image: ghcr.io/zammad/zammad:latest
    container_name: zammad-nginx
    command: ["zammad-nginx"]
    ports:
      - "8080:8080"
    depends_on:
      - zammad-railsserver
      - zammad-websocket
    volumes:
      - zammad-storage:/opt/zammad/storage
    restart: unless-stopped

  zammad-elasticsearch:
    image: bitnami/elasticsearch:8
    container_name: zammad-elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    volumes:
      - elasticsearch-data:/bitnami/elasticsearch/data
    restart: unless-stopped

  zammad-memcached:
    image: memcached:1.6-alpine
    container_name: zammad-memcached
    command: memcached -m 256
    restart: unless-stopped

  zammad-postgresql:
    image: postgres:16-alpine
    container_name: zammad-postgresql
    environment:
      POSTGRES_USER: zammad
      POSTGRES_PASSWORD: zammad
      POSTGRES_DB: zammad_production
    volumes:
      - postgresql-data:/var/lib/postgresql/data
    restart: unless-stopped

  zammad-redis:
    image: redis:7-alpine
    container_name: zammad-redis
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  zammad-storage:
  elasticsearch-data:
  postgresql-data:
  redis-data:

Starting Zammad

docker compose up -d

The first startup takes several minutes as the database is initialized and Elasticsearch indexes are built. Access Zammad at http://your-server:8080 once the railsserver container reports healthy.

Initial Setup Wizard

On first access, Zammad walks you through a setup wizard:

  1. Create admin account -- Set your admin username, email, and password
  2. Organization name -- Your company or team name
  3. Email notification settings -- Configure SMTP for outbound notifications
  4. Email channel -- Connect an email account to receive tickets via email
  5. Base URL -- Set the public URL where Zammad is accessible

Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.

Configuring Email Channels

Email is usually the primary channel for a helpdesk. Zammad can connect to email accounts via IMAP/POP3 and send replies via SMTP.

Adding an email channel

  1. Go to Admin > Channels > Email
  2. Click Add Email Account
  3. Enter the email address (e.g., [email protected])
  4. Configure IMAP settings (server, port, credentials)
  5. Configure SMTP settings for sending
  6. Set the default group (ticket queue) for incoming emails

Zammad polls the mailbox periodically and creates tickets for new messages. Replies from agents are sent via SMTP with proper threading headers, so the conversation appears correctly in the customer's email client.

Multiple email addresses

You can add multiple email channels for different purposes:

Each address can route to a different group with different agents and SLA rules.

Knowledge Base

Zammad includes a built-in knowledge base for self-service support. Agents can write articles, organize them into categories, and make them publicly accessible or internal-only.

Setting up the knowledge base

  1. Go to Admin > Knowledge Base
  2. Enable the knowledge base and configure the public URL
  3. Create categories (e.g., "Getting Started", "Billing", "API Documentation")
  4. Write articles with the rich text editor
  5. Set visibility: public (accessible without login), internal (agents only), or draft

The knowledge base supports full-text search and can be embedded in your website or linked from automated ticket responses.

SLA Management

Service Level Agreements define your response time commitments. Zammad tracks SLA compliance per ticket and escalates when deadlines approach.

Configuring SLAs

  1. Go to Admin > SLAs
  2. Create an SLA with conditions (e.g., applies to tickets in the "Support" group with "High" priority)
  3. Set time targets:
    • First response time -- How quickly the first agent reply should happen
    • Update time -- Maximum time between agent replies
    • Solution time -- Total time to resolve the ticket
  4. Define business hours (SLA clocks only tick during working hours)

When a ticket approaches or exceeds its SLA deadline, it's highlighted in the ticket queue and can trigger escalation notifications.

Triggers and Automations

Triggers fire when specific conditions are met on ticket creation or update.

Common trigger examples

Auto-assign based on email address:

Auto-respond to new tickets:

Escalation notification:

Tag based on content:

Zammad vs Alternatives

Feature Zammad FreeScout osTicket GLPI
Language Ruby on Rails PHP (Laravel) PHP PHP
RAM usage 2-4 GB 256-512 MB 256-512 MB 512 MB-1 GB
UI quality Excellent Good Dated Functional
Multi-channel Email, chat, social, phone Email + modules Email, web forms Email, web forms
Knowledge base Built-in Plugin Built-in (basic) Built-in
SLA management Yes No (paid module) Basic Yes
Full-text search Elasticsearch Database Database Database
Real-time updates WebSocket Polling Polling Polling
API REST REST Limited REST
LDAP/SSO Yes No (paid) LDAP plugin Yes
Asset management No No No Yes (core feature)
Learning curve Moderate Low Low Moderate

Choose Zammad when

Choose FreeScout when

Choose osTicket when

Choose GLPI when

Reverse Proxy Configuration

Zammad's bundled Nginx container listens on port 8080. Put it behind your existing reverse proxy for HTTPS:

Caddy:

support.yourdomain.com {
    reverse_proxy localhost:8080
}

Nginx:

server {
    server_name support.yourdomain.com;

    client_max_body_size 50M;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }

    location /ws {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Backup Strategy

Back up the PostgreSQL database and the storage volume:

# Database backup
docker exec zammad-postgresql pg_dump -U zammad zammad_production > zammad-backup-$(date +%Y%m%d).sql

# Storage backup (attachments, images)
docker run --rm -v zammad-storage:/data -v $(pwd):/backup alpine \
  tar czf /backup/zammad-storage-$(date +%Y%m%d).tar.gz /data

Elasticsearch data does not need to be backed up separately -- it can be rebuilt from the database using zammad run rails r 'SearchIndexBackend.reindex'.

Production Tips

Resource tuning

Email deliverability

Ensure your outbound emails don't land in spam:

Keeping Zammad updated

docker compose pull
docker compose up -d

Zammad publishes regular releases with security fixes and new features. Major version upgrades occasionally require database migrations, which run automatically on container startup.

Verdict

Zammad is the most polished self-hosted helpdesk available. The multi-channel support, SLA management, and knowledge base put it in the same category as commercial tools costing $50-100 per agent per month. The trade-off is resource consumption -- you need a server with real headroom to run Elasticsearch, PostgreSQL, Redis, and the Rails application comfortably.

For small teams that just need email ticketing, FreeScout or osTicket will serve you well with far fewer resources. But if your support operation has outgrown a shared inbox and you need proper SLA tracking, multi-channel support, and a UI your agents won't dread opening every morning, Zammad delivers. The setup is heavier than most self-hosted tools, but the result is a helpdesk that competes with the commercial options on features while keeping your data entirely under your control.

Get free weekly tips in your inbox. Subscribe to Self-Hosted Weekly