OTRS 6 migration to Zammad (test instance for evaluation)


I wanted to start a thread to share how I migrated OTRS 6 to Zammad to evaluate the use of Zammad within our organisation and will use this thread to keep track of my findings and experience.

I am thankful for all contributions to this forum and would like to thank every contributor. This would not have been possible without you!

Use case

IT Support for a regional schools’ network
5 Service centers (sites where agents are located)
~150 Organisations
~230 Sites (an organisation can have more than one site)


  • Version
  • OS Centos 7
  • Apache2 (httpd)
  • 1229 users (agents and customers)
  • 51668 tickets


  • Version 6.2.0-1707172848.16867851.bookworm
  • OS Debian 12
    • OS and SSH hardening
    • Unattended updates for security updates
  • PostgreSQL 15
  • nginx
  • Distribution package installation (not docker, not source code)

Migration time 6h on a notebook with two VMs on Hyper-V and 16GB RAM in total

Migration setup

OTRS6 Server

  • Activate unsigned packages support
  • Install migration plugins following the official guide
  • Avoid OOM (Out of memory)
    • Create a file with the path /etc/httpd/conf.d/mpm_prefork.conf, and add the following command block to the file:
    <IfModule mpm_prefork_module>  
    StartServers 5  
    MinSpareServers 5  
    MaxSpareServers 10  
    MaxRequestWorkers 30  
    MaxConnectionsPerChild  0  
  • Test configuration
    httpd -t
  • Restart httpd
    systemctl restart httpd

Zammad Server Setup

  • Set file storage for attachments before import

    • (as root)
    zammad run rails c
    Setting.set('storage_provider', 'File')
  • Import via CLI

    • Set parameters, enter import mode and start import
      (continue in the rails console)
    Setting.set('import_otrs_endpoint', 'https://support.example.com/otrs/public.pl?Action=ZammadMigrator')
    Setting.set('import_otrs_endpoint_key', '<YOURKEY>')
    Setting.set('import_mode', true)

    Once done exit import mode

    Setting.set('import_mode', false)
    Setting.set('system_init_done', true)

Troubleshooting post import

CSRF token verification failed

Since OTRS 6 was running with a SSL certificate, we need to set up a self signed SSL certificate in Zammad to avoid the issue (reminder this is an evalutation installation and not production, therefore we will not register an SSL cert)

  • Set up a self signed SSL for nginx
    apt-get install openssl
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx.key -out /etc/ssl/certs/nginx.crt
    openssl dhparam -out /etc/nginx/dhparam.pem 4096
    Add /etc/nginx/snippets/self-signed.conf
    ssl_certificate /etc/ssl/certs/nginx.crt;
    ssl_certificate_key /etc/ssl/private/nginx.key;
    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 10m;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver valid=300s;
    resolver_timeout 5s;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    ssl_dhparam /etc/nginx/dhparam.pem;
    ssl_ecdh_curve secp384r1;

Open issues

file-2 attachment

Like https://community.zammad.org/t/file-1-file-2-attachment-after-migration-from-otrs/9276 - No solution found yet.
Since these are old tickets to be kept as archive. I do personally not see it as issue

Rethinking the structure

The goal is to have a correct group/organization structure and notifications for the agents
This is the hardest part as I am trying to figure out how that works correctly.

1 Organization (A)
3 Sites (A1, A2, A3)
3 Customers (CA1, CA2, CA3)
3 Technicians (TA1, TA2, TA3)

New tickets should be assigned to the correct technician (e.g. TA1 for tickets from CA1 for A1) but all other TA (or TB3 or TC4 for other organizations) should not be notified or see the ticket

Set up email boxes (or better MS365 channels)

Same as above, I still need some time to figure out how the things are connected correctly and how to set it up appropriately. I hope I’ll be able to share the setups too

Open points

Try OpenSearch

I know it is not supported, but it’s a good time to start trying it out before putting it in production

Testing with Agents and Customers


Excuse the wall of text and have a good day.

I delved into the various setups within Zammad, exploring its configurations involving groups, organizations, roles, users, permissions, and notifications.

From what I understood, what was previously termed a “queue” in OTRS now corresponds to a “group” in Zammad. Although direct connections between groups and users or roles aren’t feasible, group permissions can be established at either the role or user level.

The organization setting serves purposes such as user filtering, trigger definition, and overview establishment, yet it does not impact groups, notifications, or permissions significantly, apart from facilitating ticket sharing among organization-affiliated customers.
Given that our users all share the same email domain managed at a regional level, filtering by domain name isn’t viable.

Use Case:

  • A school may belong to a group of schools (Sprengel).
  • Support requests from a school are submitted via web and email.
  • Each school may have one or more teachers requesting support (customers).
  • A school typically has one main technician and a backup technician (agents).

How To:

  • Establish one organization per school, rather than per school group (Sprengel), with shared organization disabled.
  • (Optional) Modify organization object to add field for school group (Sprengel)
  • Create one organization per service center (agent site).
  • Set up a distinct group for each school.
  • Designate a group as “SUPPORT” to ensure all tickets are routed there, simplifying the user experience for teachers (customers).
  • Create one role per service center.
  • Link customers to their respective schools (main organization).
  • Assign technicians (agents) to the service center (main organization) and schools (secondary organizations).
  • For each technician (agent, not role), specify the school(s) (group) they primarily serve as well as their backup school(s) (group), granting them FULL Group Permissions to ensure they receive Zammad notifications and emails.
  • Implement a trigger for every group to ensure that when a ticket with status new from a specific school (organization) within the “SUPPORT” group is moved to the corresponding school group (group).

This setup ensures:

  • Every teacher’s (customer) request is directed to the designated technician (and backup technician) (agent)
  • Only specified technicians (agent) receive notifications via Zammad and email.

Did I overlook anything?

Next on the agenda: configuring the MS365 channel, which may present challenges due to the lack of testing capabilities.

Technical update

Zammad is being installed on virtual machines with Ubuntu 22.04 using ansible (for repeatability, compliance, etc…). Mainly inspired by https://github.com/hifis-net/ansible-role-zammad (thank you!)


Zammad, Elasticsearch and PostgreSQL are being installed on three different servers (redis might follow). Since Zammad has hard dependencies on elasticsearch, postgresql and other packages like redis, there is no way to install services on separate servers.


To solve it I am building dummy packages of the hard dependecies using equivs on the Zammad server. It is not perfect but makes installing Zammad on a cloud like environment possible.

In any case this is how I set up Zammad, Postgresql and Elasticsearch-oss on three different servers with ansible

It is a custom working solution and might not work with every setup, so please if at all, only use it as reference.