Swiss...
Complete Guide: Migrating from Zimbra OSE to Carbonio CE
A real-world walkthrough for migrating years of email with zero data loss.
May 15, 2026
by Ezequiel Pineda 35 min read
Email server migration from Zimbra to Carbonio

A step-by-step, battle-tested guide to migrating years of email from Zimbra 8.8.x on CentOS 7 to Carbonio Community Edition on Ubuntu 24.04 — with zero data loss.

Introduction

If you're running Zimbra Open Source Edition on CentOS 7, you're sitting on two ticking time bombs. CentOS 7 reached end-of-life in June 2024 — no more security patches, no more updates. And Zimbra's open-source edition? Synacor stopped releasing it after version 8.8.15. Zimbra 9 and 10 are commercial-only, requiring paid licenses.

This guide documents a real production migration we performed: moving a multi-domain mail server with ~30 accounts and 3.5GB of mail from Zimbra 8.8.11 on CentOS 7 to Carbonio Community Edition on Ubuntu 24.04. Every command in this guide was run on a live system. Every gotcha documented here was encountered and solved in real time.

Who this guide is for: System administrators running Zimbra OSE who need a migration path that preserves all email, passwords, and configurations without requiring a commercial license.

What is Carbonio CE? Carbonio Community Edition is a free, open-source email and collaboration platform built by Zextras — the same team behind the popular Zextras Suite for Zimbra. It's the direct spiritual successor to Zimbra OSE, built on the same underlying stack (Postfix, OpenLDAP, Jetty), with a modern web interface and active development.

Why Migrate from Zimbra to Carbonio?

Zimbra OSE is dead. The last open-source release was 8.8.15. If you want Zimbra 9 or 10, you need a Network Edition license — roughly $960/year for every 25 mailboxes. For a small hosting company or organization running 30-50 accounts, that's an ongoing cost for something that used to be free.

CentOS 7 is dead. No security patches since June 2024. Every day your mail server runs on it is a day you're exposed to unpatched vulnerabilities.

Carbonio CE is the natural successor. Same CLI tools (zmprov, zmmailbox), same directory structure (/opt/zextras/), same LDAP backend. If you know Zimbra, you already know 90% of Carbonio. The migration path is well-documented, and the community is growing as Zimbra OSE users make the switch.

Pre-Migration Planning

Inventory Your Current Setup

Before touching anything, document what you have. On your existing Zimbra server, run these as the zimbra user (use the -l flag to bypass any SSL issues with expired certificates):

# List all domains
zmprov -l getAllDomains

# List all accounts
zmprov -l gaa

# Export all accounts with password hashes
zmprov -l gaa -v | grep -E "^(# name|userPassword:)" > /opt/zimbra/backup/passwords_full.txt

# Export aliases
zmprov -l gaa -v | grep -E "^(# name|zimbraMailAlias)" > /opt/zimbra/backup/aliases.txt

# Export distribution lists
zmprov -l gadl > /opt/zimbra/backup/distlists.txt

# Check mailstore size
du -sh /opt/zimbra/store/

# Verify IMAP is enabled
zmprov -l gs $(hostname) zimbraImapServerEnabled

Save all of this output somewhere safe — off the server. This is your migration blueprint.

Key Decisions

Operating System: Carbonio CE officially supports Ubuntu 22.04 and Ubuntu 24.04. Rocky Linux works but isn't officially supported and may require manual dependency fixes. We strongly recommend Ubuntu 24.04 LTS for the smoothest installation.

Migration Method: We'll use imapsync — it works over the IMAP protocol, is version-agnostic, and allows you to run migrations while the old server is still live. It's resumable, incremental, and never deletes anything on either side by default.

Hostname Strategy: Use a temporary hostname (e.g., webmail.yourdomain.com) for the new server during setup and testing. Keep the old server running on the production hostname until you're ready to cut over.

Step 1: Prepare the New Server

Start with a fresh Ubuntu 24.04 LTS Server installation. Ensure it has a public IP address, at least 4GB RAM, and sufficient storage for your mailstore plus room to grow.

Set the Hostname
hostnamectl set-hostname mail.example.com
Configure /etc/hosts

Carbonio requires a clean hosts file with no IPv6 entries:

cat > /etc/hosts << EOF
127.0.0.1 localhost
203.0.113.10 mail.example.com mail
EOF

Verify:

hostname -f  # Should return: mail.example.com
hostname -i  # Should return: 203.0.113.10
Verify Locale
locale | grep LANG

Must show en_US.UTF-8. If not, configure it before proceeding.

Disable cloud-init (if applicable)

If you're on a VM and want to prevent cloud-init from resetting your network configuration:

touch /etc/cloud/cloud-init.disabled

Step 2: Install Carbonio CE

Add Repositories

Zextras repository:

wget -O- "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x5dc7680bc4378c471a7fa80f52fd40243e584a21" | gpg --dearmor | sudo tee /usr/share/keyrings/zextras.gpg > /dev/null

sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/zextras.gpg] https://repo.zextras.io/release/ubuntu noble main" > /etc/apt/sources.list.d/zextras.list'

PostgreSQL 16 repository:

echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list

wget -O- "https://www.postgresql.org/media/keys/ACCC4CF8.asc" | gpg --dearmor | sudo tee /usr/share/keyrings/postgres.gpg > /dev/null

chmod 644 /usr/share/keyrings/postgres.gpg

sed -i 's/deb/deb [signed-by=\/usr\/share\/keyrings\/postgres.gpg] /' /etc/apt/sources.list.d/pgdg.list

Update and verify:

apt update
apt-cache search carbonio | head -5
apt-cache search postgresql-16 | head -3
Install and Configure PostgreSQL
apt install -y postgresql-16
systemctl enable postgresql
systemctl start postgresql

# Generate a secure password
PGPASS="$(openssl rand -base64 24)"
echo "Save this PostgreSQL password: $PGPASS"

# Create the Carbonio database
su - postgres -c "psql --command=\"CREATE ROLE carbonio_adm WITH LOGIN SUPERUSER PASSWORD '$PGPASS';\""
su - postgres -c "psql --command=\"CREATE DATABASE carbonio_adm owner carbonio_adm;\""
su - postgres -c "psql --command=\"ALTER SYSTEM SET listen_addresses TO '*';\""
su - postgres -c "psql --command=\"ALTER SYSTEM SET max_connections = 500;\""
su - postgres -c "psql --command=\"ALTER SYSTEM SET shared_buffers = 5000;\""
echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/16/main/pg_hba.conf
systemctl restart postgresql

Important: Save the PostgreSQL password. You'll need it during the Carbonio bootstrap.

Install Carbonio Packages
apt install -y \
  service-discover-server \
  carbonio-directory-server \
  carbonio-proxy \
  carbonio-webui \
  carbonio-mta \
  carbonio-appserver \
  carbonio-storages-ce \
  carbonio-message-broker \
  carbonio-user-management
Bootstrap Carbonio
carbonio-bootstrap

This interactive process will detect your domain from the hostname and present a configuration menu. Go into option 1 (Common Configuration) to set the admin password. Save it. Then press y to apply.

Set Up Carbonio Mesh
service-discover setup-wizard

Enter your server's IP with subnet mask (e.g., 203.0.113.10/30) and create a cluster credentials password. Save this password.

Run Pending Setups
pending-setups -a
Install Additional Required Packages

From our experience, several packages are needed that aren't always pulled in automatically:

apt install -y carbonio-catalog carbonio-memcached carbonio-admin-console-ui carbonio-webui
pending-setups -a

Important: The carbonio-admin-console-ui and carbonio-admin-ui packages conflict with each other. If you install carbonio-admin-ui by mistake, it will remove carbonio-admin-console-ui and your admin panel sidebar will be empty. If this happens:

apt install -y carbonio-admin-console-ui

After installing the correct UI packages, prevent them from being auto-removed:

apt-mark manual carbonio-admin-login-ui carbonio-auth-ui carbonio-calendars-ui carbonio-contacts-ui carbonio-login-ui carbonio-mails-ui carbonio-search-ui carbonio-shell-ui
Verify Services

On Ubuntu 24.04, Carbonio services are managed via systemd, not zmcontrol:

systemctl list-units 'carbonio-*' --type=service --state=running

You should see 30+ services running. Access the admin panel at https://your-server-ip:6071 with the admin credentials you set during bootstrap.

Step 3: Migrate Accounts and Passwords

Add Domains

On the new Carbonio server, add each domain from your old server (the default domain is created during bootstrap):

su - zextras -c "zmprov cd yourdomain.com"
su - zextras -c "zmprov cd anotherdomain.com"
Create Accounts

Create all user accounts (skip system accounts like galsync, spam, ham, virus-quarantine):

su - zextras << 'EOF'
zmprov ca user@yourdomain.com 'TempPass123!'
zmprov ca support@yourdomain.com 'TempPass123!'
zmprov ca billing@yourdomain.com 'TempPass123!'
EOF
Import Password Hashes

This is critical — it allows users to keep their existing passwords. Copy the passwords_full.txt file from the old server to the new server, then run:

while IFS= read -r line; do
  if [[ "$line" =~ ^"# name "(.+) ]]; then
    acct="${BASH_REMATCH[1]}"
  elif [[ "$line" =~ ^"userPassword: "(.+) ]]; then
    hash="${BASH_REMATCH[1]}"
    echo "Setting password for $acct"
    su - zextras -c "zmprov ma '$acct' userPassword '$hash'" 2>/dev/null
  fi
done < /tmp/passwords_full.txt

System accounts that don't exist on the new server will silently fail — that's expected and harmless.

Import Aliases

Based on your alias export, create them on the new server:

su - zextras -c "zmprov aaa user@yourdomain.com alias@yourdomain.com"
Set Display Names

Without display names, outgoing emails may show generic names in recipients' inboxes:

su - zextras -c "zmprov ma user@yourdomain.com displayName 'John Smith'"

Step 4: Migrate Email with imapsync

Install imapsync

imapsync isn't in the Ubuntu 24.04 repositories. Install it manually:

apt install -y libauthen-ntlm-perl libcgi-pm-perl libcrypt-openssl-rsa-perl \
  libdata-uniqid-perl libencode-imaputf7-perl libfile-copy-recursive-perl \
  libfile-tail-perl libio-compress-perl libio-socket-inet6-perl \
  libio-socket-ssl-perl libio-tee-perl libhtml-parser-perl \
  libjson-webtoken-perl libmail-imapclient-perl libparse-recdescent-perl \
  libproc-processtable-perl libmodule-scandeps-perl libreadonly-perl \
  libregexp-common-perl libsys-meminfo-perl libterm-readkey-perl \
  libtest-mockobject-perl libtest-pod-perl libunicode-string-perl \
  liburi-perl libwww-perl libtest-nowarnings-perl libtest-deep-perl \
  libtest-warn-perl make cpanminus

cpanm JSON::WebToken

wget -O /usr/local/bin/imapsync https://raw.githubusercontent.com/imapsync/imapsync/master/imapsync
chmod +x /usr/local/bin/imapsync
imapsync --version
Increase Message Size Limit

Before migrating, increase the maximum message size to avoid errors with large emails:

su - zextras -c "zmprov mcf zimbraMtaMaxMessageSize 52428800"
su - zextras -c "zmprov mcf zimbraFileUploadMaxSize 52428800"
su - zextras -c "zmprov mcf zimbraMailContentMaxSize 52428800"
Test Authentication

Run a dry test on a single account first:

imapsync --host1 OLD_SERVER_IP --ssl1 --sslargs1 SSL_verify_mode=0 \
  --authuser1 admin@mail.example.com --user1 user@example.com --password1 'ADMIN_PASS' \
  --host2 localhost --ssl2 --sslargs2 SSL_verify_mode=0 \
  --authuser2 zextras@example.com --user2 user@example.com --password2 'NEW_ADMIN_PASS' \
  --dry --addheader

The --dry flag means no data is copied — it just tests authentication. If both sides authenticate, you're ready.

Create the Migration Script
cat > /root/migrate.sh << 'SCRIPT'
#!/bin/bash

ACCOUNTS="
user@yourdomain.com
support@yourdomain.com
billing@yourdomain.com
"

for acct in $ACCOUNTS; do
  echo "========================================"
  echo "Syncing: $acct"
  echo "Started: $(date)"
  echo "========================================"
  imapsync --host1 OLD_SERVER_IP --ssl1 --sslargs1 SSL_verify_mode=0 \
    --authuser1 admin@mail.example.com --user1 "$acct" --password1 'ADMIN_PASS' \
    --host2 localhost --ssl2 --sslargs2 SSL_verify_mode=0 \
    --authuser2 zextras@example.com --user2 "$acct" --password2 'NEW_ADMIN_PASS' \
    --addheader
  echo "Finished: $acct at $(date)"
  echo ""
done

echo "ALL ACCOUNTS MIGRATED"
SCRIPT

chmod +x /root/migrate.sh
Run the Migration

Always run inside a screen session to survive disconnections:

screen -S migration
bash /root/migrate.sh 2>&1 | tee /root/migration.log

Detach with Ctrl+A then D. Reattach with screen -r migration.

Why imapsync is Safe

imapsync deserves special mention for anyone nervous about migrating years of email:

  • It's additive only by default — it never deletes anything on either side
  • It's resumable — if interrupted, just run it again and it picks up where it left off
  • It gives you detailed logs per account for verification
  • You can dry-run first with --dry
  • You run it while the old server is live — users keep working, mail keeps flowing
  • At no point does mail exist in only one place
Post-Migration Verification

After migration completes, check for errors:

grep -i "Detected [1-9]" /root/migration.log

Common errors you'll see are "maximum message size exceeded" for messages larger than the default 10MB limit. If you set the size limit to 50MB as shown above and re-run the script, imapsync will pick up only the failed messages.

Step 5: SSL Certificates with Let's Encrypt

Install Certbot
apt install -y certbot
Generate the Certificate

Stop nginx temporarily for the standalone challenge:

systemctl stop carbonio-nginx.service
certbot certonly --standalone -d mail.example.com -d mail.anotherdomain.com
Download the Root CA

Carbonio's certificate verification requires the full chain including the root CA:

wget -O /opt/zextras/ssl/carbonio/isrg-root-x1.pem https://letsencrypt.org/certs/isrgrootx1.pem
Deploy to Carbonio
DOMAIN="mail.example.com"

cp /etc/letsencrypt/live/$DOMAIN/privkey.pem /opt/zextras/ssl/carbonio/commercial/commercial.key
cp /etc/letsencrypt/live/$DOMAIN/cert.pem /opt/zextras/ssl/carbonio/commercial/commercial.crt
cat /etc/letsencrypt/live/$DOMAIN/chain.pem /opt/zextras/ssl/carbonio/isrg-root-x1.pem > /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt
chown zextras:zextras /opt/zextras/ssl/carbonio/commercial/*

Verify the certificate chain:

su - zextras -c "/opt/zextras/bin/zmcertmgr verifycrt comm \
  /opt/zextras/ssl/carbonio/commercial/commercial.key \
  /opt/zextras/ssl/carbonio/commercial/commercial.crt \
  /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt"

Deploy it:

su - zextras -c "/opt/zextras/bin/zmcertmgr deploycrt comm \
  /opt/zextras/ssl/carbonio/commercial/commercial.crt \
  /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt"

Restart services:

systemctl restart carbonio-proxy.target carbonio-mta.target carbonio-appserver.target
Set Up Auto-Renewal

Create a deploy hook so certificates are automatically deployed to Carbonio when renewed:

cat > /etc/letsencrypt/renewal-hooks/deploy/carbonio-deploy.sh << 'SCRIPT'
#!/bin/bash
DOMAIN="mail.example.com"

cp /etc/letsencrypt/live/$DOMAIN/privkey.pem /opt/zextras/ssl/carbonio/commercial/commercial.key
cp /etc/letsencrypt/live/$DOMAIN/cert.pem /opt/zextras/ssl/carbonio/commercial/commercial.crt
cat /etc/letsencrypt/live/$DOMAIN/chain.pem /opt/zextras/ssl/carbonio/isrg-root-x1.pem > /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt
chown zextras:zextras /opt/zextras/ssl/carbonio/commercial/*

su - zextras -c "/opt/zextras/bin/zmcertmgr deploycrt comm \
  /opt/zextras/ssl/carbonio/commercial/commercial.crt \
  /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt"

systemctl restart carbonio-proxy.target carbonio-mta.target carbonio-appserver.target
SCRIPT

chmod +x /etc/letsencrypt/renewal-hooks/deploy/carbonio-deploy.sh

Test the renewal:

certbot renew --dry-run

Step 6: Security Hardening

fail2ban for Brute Force Protection

If your mail server is publicly accessible (and it is), brute force attacks against IMAP, POP3, and SMTP authentication are inevitable. We've seen competitors deliberately brute-force login attempts to trigger account lockouts on Zimbra servers — disabling legitimate access.

apt install -y fail2ban

Create the Carbonio filter:

cat > /etc/fail2ban/filter.d/carbonio.conf << 'EOF'
[Definition]
failregex = \[ip=;\] account - authentication failed for .* \(no such account\)$
            \[ip=;\] security - cmd=Auth; .* error=authentication failed for .*, invalid password;$
            ;oip=;.* security - cmd=Auth; .* protocol=soap; error=authentication failed for .* invalid password;$
            \[oip=;.* SoapEngine - handler exception: authentication failed for .*, account not found$
            WARN .*;ip=;ua=CarbonioWebClient .* security - cmd=AdminAuth; .* error=authentication failed for .*;$
            ;oip=;.* security - cmd=AdminAuth; .* error=authentication failed for .*
            zm lookup: .* user not found:.* client: :\d+, server:
            An error occurred in mail zmauth: .* client: :\d+, server:
            NOQUEUE: reject: RCPT from .*\[\]: 550 5.1.1 .*: Recipient address rejected:
ignoreregex =
EOF

Create the jails:

cat > /etc/fail2ban/jail.d/carbonio.conf << 'EOF'
[carbonio]
enabled  = true
filter   = carbonio
backend  = polling
logpath  = /opt/zextras/log/audit.log
           /opt/zextras/log/nginx.log
           /var/log/mail.log
maxretry = 5
bantime  = 3600
findtime = 600
action   = iptables-multiport[name=carbonio, port="25,80,110,143,443,465,587,993,995,6071", protocol=tcp]

[carbonio-smtp]
enabled  = true
filter   = carbonio
backend  = polling
logpath  = /var/log/mail.log
maxretry = 3
bantime  = 7200
findtime = 600
action   = iptables-multiport[name=carbonio-smtp, port="25,465,587", protocol=tcp]
EOF

Critical: The backend = polling line is essential. On Ubuntu 24.04, fail2ban's default inotify backend does not properly monitor Carbonio's log files. Without backend = polling, your jails will load but never detect any failures. This cost us significant debugging time.

Start fail2ban:

systemctl enable fail2ban
systemctl restart fail2ban
fail2ban-client status

You should see three jails: sshd, carbonio, and carbonio-smtp. When an IP gets banned from the carbonio jail, it's blocked on all mail ports simultaneously (25, 80, 110, 143, 443, 465, 587, 993, 995, and 6071).

Service Account COS (Class of Service)

If you have service accounts that need to connect reliably (like a billing system pulling email via POP3), create a COS that disables password lockout. Combined with fail2ban blocking brute force at the IP level, this gives you both security and reliability:

su - zextras -c "zmprov cc ServiceAccountCOS zimbraPasswordLockoutEnabled FALSE"

Get the COS ID and assign it:

# Get the COS ID
su - zextras -c "zmprov gc ServiceAccountCOS | grep zimbraId"

# Assign to service accounts
su - zextras -c "zmprov ma serviceaccount@example.com zimbraCOSId YOUR_COS_ID"

Step 7: DNS Configuration and Cutover

DNS Records Required

Before switching over, prepare all DNS records:

A Record:

mail.example.com → YOUR_NEW_SERVER_IP

MX Record (usually doesn't need changing if it already points to mail.example.com):

example.com MX 10 mail.example.com

SPF Record:

v=spf1 mx a ip4:YOUR_NEW_SERVER_IP/32 -all

PTR (Reverse DNS):

YOUR_NEW_SERVER_IP → mail.example.com

DKIM: Generate on the new server:

su - zextras -c "/opt/zextras/libexec/zmdkimkeyutil -a -d example.com"

This outputs a TXT record to add to DNS. Remove any old DKIM records from the previous server.

DMARC:

_dmarc.example.com TXT "v=DMARC1; p=quarantine; rua=mailto:admin@example.com; ruf=mailto:admin@example.com; fo=1; pct=100; adkim=s; aspf=s"
The Cutover
  1. Lower DNS TTLs to 300-600 seconds a few days before cutover
  2. Update the A record to point to the new server
  3. Run one final imapsync delta to catch any mail delivered to the old server during propagation
  4. Verify with dig +short mail.example.com @8.8.8.8 and @1.1.1.1
  5. Regenerate the Let's Encrypt certificate for the production hostname
  6. Test by sending email to an external provider (Gmail) and checking headers for SPF/DKIM/DMARC PASS
Verification

Send a test email to Gmail and check the original message headers:

SPF: PASS with IP YOUR_NEW_SERVER_IP
DKIM: 'PASS' with domain example.com
DMARC: 'PASS'

All three should show PASS. If they do, your migration is complete.

Common Issues and Troubleshooting

Amavis OpenSSL Mismatch (Ubuntu 24.04)

Symptom: Outgoing email fails with "451 4.7.1 Service unavailable - try again later." The mail log shows amavis processes starting and immediately exiting.

Cause: Carbonio's bundled libssl.so.3 requires OpenSSL 3.3.0 symbols, but Ubuntu 24.04's system libcrypto.so.3 only provides 3.0.x. The version mismatch causes amavis to crash.

Fix: Create a systemd override to use Carbonio's own OpenSSL libraries:

systemctl edit carbonio-mailthreat.service

Add between the comment markers:

[Service]
Environment="LD_LIBRARY_PATH=/opt/zextras/common/lib"

Then:

systemctl daemon-reload
systemctl restart carbonio-mailthreat.service

Verify amavis is staying alive:

systemctl status carbonio-mailthreat.service

You can confirm the fix was necessary by checking:

strings /opt/zextras/common/lib/libcrypto.so.3 | grep OPENSSL_3.3.0
Amavis Config File Ownership

Symptom: amavisd refuses to start with "Config file should not be owned by EUID 996."

Fix: Amavis has a security check that refuses to load a config owned by the same user running it. The config must be owned by root:

chown root:zextras /opt/zextras/conf/amavisd.conf
Admin Panel Shows "Something Went Wrong"

Symptom: You can log into the admin panel but the page shows an error.

Cause: Usually the carbonio-catalog package is not installed, or there's a conflict between carbonio-admin-ui and carbonio-admin-console-ui.

Fix:

apt install -y carbonio-catalog carbonio-admin-console-ui
pending-setups -a
systemctl restart carbonio-nginx.service
Empty Admin Panel Sidebar

Symptom: The admin panel loads and you can log in, but the sidebar has no navigation items and the CREATE button doesn't work.

Cause: The carbonio-admin-console-ui package was removed when carbonio-admin-ui was installed (they conflict).

Fix:

apt install -y carbonio-admin-console-ui

Then mark UI packages to prevent auto-removal:

apt-mark manual carbonio-admin-login-ui carbonio-auth-ui carbonio-calendars-ui \
  carbonio-contacts-ui carbonio-login-ui carbonio-mails-ui \
  carbonio-search-ui carbonio-shell-ui
imapsync "Maximum Message Size Exceeded"

Symptom: Some messages fail to transfer with "BAD maximum message size exceeded."

Fix: Increase the message size limit before migration:

su - zextras -c "zmprov mcf zimbraMtaMaxMessageSize 52428800"
su - zextras -c "zmprov mcf zimbraFileUploadMaxSize 52428800"
su - zextras -c "zmprov mcf zimbraMailContentMaxSize 52428800"

Re-run the migration script — imapsync only transfers what's missing.

fail2ban Jails Load But Never Ban

Symptom: fail2ban-client status carbonio shows the jail is active but Total failed: 0 despite known failed login attempts in the logs.

Cause: On Ubuntu 24.04, fail2ban's default inotify file monitoring backend doesn't properly watch Carbonio's log files.

Fix: Add backend = polling to the jail configuration:

[carbonio]
enabled  = true
filter   = carbonio
backend  = polling
...
zmcontrol status Shows Nothing (Ubuntu 24.04)

Symptom: zmcontrol status runs but shows no services.

Cause: On Ubuntu 24.04, Carbonio uses systemd exclusively for service management. The legacy zmcontrol start/stop/restart commands are not available.

Fix: Use systemd instead:

systemctl list-units 'carbonio-*' --type=service --state=running

Post-Migration Checklist

After your cutover is complete, work through this checklist:

  • ☐ Verify email delivery by sending to external providers (Gmail, Outlook) — check SPF, DKIM, DMARC in headers
  • ☐ Verify email reception by sending from external providers to your domain
  • ☐ Test webmail login at https://mail.example.com
  • ☐ Test admin panel at https://mail.example.com:6071
  • ☐ Test IMAP connectivity on port 993
  • ☐ Test POP3 connectivity on port 995
  • ☐ Test SMTP submission on port 587
  • ☐ Verify fail2ban is operational: fail2ban-client status carbonio
  • ☐ Verify SSL certificate is valid: echo | openssl s_client -connect mail.example.com:993 2>/dev/null | grep issuer
  • ☐ Verify certbot auto-renewal: certbot renew --dry-run
  • ☐ Update any external applications (billing systems, CRM, phone clients) to point to the new server
  • ☐ Run a final imapsync delta 24-48 hours after cutover
  • ☐ Keep the old server running for at least one week as a safety net
  • ☐ Monitor /var/log/mail.log for any delivery issues
  • ☐ Monitor /opt/zextras/log/audit.log for authentication issues

Conclusion

Migrating from Zimbra OSE to Carbonio CE is not just feasible — with the right approach, it's straightforward. The combination of imapsync for safe, incremental email transfer and Carbonio's Zimbra-compatible CLI tools means the learning curve is minimal.

The hardest part isn't the migration itself — it's the decision to stop procrastinating and do it. Your CentOS 7 box isn't getting any younger, and every day without patches is a liability.

What we covered in this guide:

  • Full Carbonio CE installation on Ubuntu 24.04
  • Account and password migration preserving existing credentials
  • Email migration with imapsync (safe, resumable, zero-downtime)
  • Let's Encrypt SSL with automatic renewal and deployment
  • fail2ban brute force protection with tested, working configurations
  • DNS cutover with SPF, DKIM, and DMARC verification
  • Real-world troubleshooting for issues you'll actually encounter

The entire migration for our ~30-account, 3.5GB setup was completed in a single working session. Larger deployments will take proportionally longer for the imapsync phase, but the process is identical.

Need infrastructure for your email server migration? SwissLayer provides managed hosting solutions with enterprise-grade network security, including Cisco ACL-protected environments, private VLANs, and Swiss data privacy standards. Whether you're migrating from Zimbra or building from scratch, we've got the infrastructure to support it.