SOGo 5.12.9 auf ARM64 mit Docker Compose und ISPConfig – Komplettanleitung

Warum SOGo selbst hosten?

SOGo (Scalable OpenGroupware.org) ist eine Open-Source-Groupware-Lösung mit Webmail, Kalender (CalDAV), Kontakten (CardDAV) und ActiveSync-Unterstützung. Perfekt als selbst-gehosteter Ersatz für Google Workspace oder Microsoft 365 – komplett unter eigener Kontrolle.

In dieser Anleitung baust du SOGo komplett von Source auf einem ARM64-Server (z.B. Raspberry Pi 5, Ampere, AWS Graviton) und integrierst es mit ISPConfig und deinem eigenen Mailserver – alles als Docker-Compose-Stack.

Architektur

                     ┌──────────────┐
                     │   Nginx      │ (SSL, Reverse Proxy)
                     │   :443       │
                     └──────┬───────┘
                            │
                     ┌──────▼───────┐
                     │   Apache     │ (SOGo VirtualHost)
                     │   :80        │
                     └──┬───────┬──┘
                        │       │
          ┌─────────────▼─┐  ┌──▼─────────────┐
          │ SOGo (sogod)  │  │ Static Files    │
          │ Port 20000    │  │ /WebServerRes. │
          └───────┬───────┘  └────────────────┘
                  │
    ┌─────────────┼─────────────┐
    │             │             │
┌───▼────┐  ┌────▼────┐  ┌─────▼──────┐
│PostgreSQL│ │Memcached│ │ Sphinx      │
│DB :5432  │ │ :11211  │ │ Fulltext    │
└──────────┘ └─────────┘ │ :9306/9312  │
                          └────────────┘

Warum SOGo auf ARM64 selbst bauen?

Die kurze Antwort: Weil es keine fertigen ARM64-Docker-Images für SOGo gibt. Die offiziellen Pakete von sogo.nu liefern nur Binaries für AMD64/x86_64. Wenn du also auf einem Raspberry Pi 5, einem Ampere-Server oder einem AWS Graviton (alles ARM64) betreibst, MUSST du SOGo selbst aus dem Quellcode kompilieren. Das ist der Grund, warum diese Anleitung existiert.

Dafür gibt es aber auch Vorteile: Du kompilierst mit den exakten Compiler-Flags für deine CPU, bindest die SSL-Bibliotheken deines Systems ein und bekommst ein optimiertes Binary – kein „tut mir leid, diese CPU wird nicht unterstützt“.

Die gute Nachricht: Dank des Multi-Stage-Dockerfile-Ansatzes machst du das genau einmal. Der Build-Container kompiliert alles, und das finale Image enthält nur die fertigen Binaries – schlank, sauber, produktionsbereit.

Was ist GNUstep – und warum braucht SOGo es?

SOGo ist in Objective-C geschrieben – der gleichen Sprache, die Apple für iOS/macOS verwendet. Objective-C benötigt zur Laufzeit eine Laufzeitumgebung, und das ist GNUstep. GNUstep ist die Open-Source-Implementierung der Cocoa-APIs (die APIs, die Apple-Entwickler kennen). Ohne GNUstep kann SOGo nicht laufen.

Concret bedeutet das: Bevor wir SOGo kompilieren können, müssen wir SOPE (das „Foundation-Framework“ von SOGo) bauen. Das ist die Basis-Bibliothek, auf der SOGo aufsetzt. SOPE und SOGo werden nacheinander im Builder-Container gebaut, dann kopieren wir nur die kompilierten Bibliotheken ins finale Image.

Das klingt aufwendig – und das ist es auch (der Build dauert ~30 Minuten). Aber das Ergebnis ist ein maßgeschneidertes ARM64-Image für deinen Server.

Warum PostgreSQL und nicht SQLite oder MariaDB?

SOGo unterstützt offiziell PostgreSQL und MySQL/MariaDB als Datenbank-Backend. Ich empfehle PostgreSQL aus einem einfachen Grund: SOGo speichert E-Mails, Kalendereinträge und Kontakte in der Datenbank. PostgreSQL hat das beste Verhalten bei gleichzeitigen Schreibzugriffen (many concurrent writers), was bei mehreren gleichzeitigen IMAP-Verbindungen und ActiveSync-Synchronisationen entscheidend ist.

Außerdem kannst du mit PostgreSQL pg_dump konsistente Online-Backups machen, während der Dienst läuft. Bei SQLite müsstest du den Dienst stoppen. Bei MariaDB/MySQL ist die Replikation aufwändiger als mit PostgreSQLs Built-in-Streaming-Replication.

TL;DR: PostgreSQL = mehr gleichzeitige Nutzer, bessere Backup-Möglichkeiten, ausgereiftere Replikation.

Warum Apache? Wird das nicht nur für PHP genutzt?

Überraschung: SOGo verwendet Apache intern als Reverse Proxy, obwohl es eine eigenständige Anwendung (sogod) ist. Das liegt daran, dass Apache die statischen Web-Ressourcen (WebServerResources) viel effizienter ausliefert als SOGo selbst. Stell es dir so vor:

  • Nginx (extern) → terminiert SSL, proxied an den Container
  • Apache (im Container) → liefert CSS/JS/Bilder direkt aus, proxied dynamische Anfragen an sogod
  • sogod (Port 20000) → die eigentliche Groupware-Anwendung

Apache ist also nicht als „alter Hase“ hier, sondern bewusst gewählt: Seine Fähigkeit, statische Dateien mit Expires: access plus 1 year zu cachen, entlastet sogod massiv bei vielen Clients.

Warum Memcached?

SOGo speichert Session-Daten (wer ist eingeloggt, welche Ordner sind offen) in einer Session-Datenbank. Standardmäßig ist das SQLite oder PostgreSQL. Mit Memcached als Session-Backend werden Sessions im RAM gehalten – das ist 100-1000x schneller als jede Festplatten-basierte Datenbank und reduziert die Last auf PostgreSQL massiv. Gerade bei vielen gleichzeitigen Webmail-Nutzern spürst du den Unterschied sofort.

Die Konfiguration ist simpel: SOGoMemcachedHost = "memcached:11211"; – und schon läuft alles über den RAM-Cache.

1. Voraussetzungen

  • ARM64-Server mit Ubuntu 24.04 LTS (Raspberry Pi 5, VPS, etc.)
  • Docker & Docker Compose installiert
  • ISPConfig (für Mailserver-Integration und User-Verwaltung)
  • Mailserver mit IMAP/SMTP/Sieve (z.B. Dovecot + Postfix)
  • Mindestens 5 GB freier Speicher

2. Multi-Stage Dockerfile (Source Build für ARM64)

Da es keine offiziellen SOGo ARM64-Binaries gibt, kompilieren wir SOPE und SOGo selbst. Das Multi-Stage-Dockerfile hält das finale Image schlank:

FROM ubuntu:24.04 AS builder

RUN apt-get update && apt-get install -y --no-install-recommends 
    build-essential gobjc gobjc++ gnustep-make gnustep-base-runtime 
    gnustep-base-common libgnustep-base-dev libxml2-dev libldap2-dev 
    libpq-dev default-libmysqlclient-dev libssl-dev libcurl4-openssl-dev 
    libsbjson-dev zlib1g-dev libsodium-dev libzip-dev uuid-dev 
    libmemcached-dev libytnef0-dev wget ca-certificates pkg-config

WORKDIR /build

# SOPE Framework
RUN wget -q https://packages.sogo.nu/sources/SOPE-5.12.9.tar.gz -O SOPE.tar.gz 
    && tar xzf SOPE.tar.gz 
    && cd SOPE-5.12.9 
    && . /usr/share/GNUstep/Makefiles/GNUstep.sh 
    && ./configure && make -j$(nproc) && make install && ldconfig

# SOGo Application
RUN wget -q https://packages.sogo.nu/sources/SOGo-5.12.9.tar.gz -O SOGo.tar.gz 
    && tar xzf SOGo.tar.gz 
    && cd SOGo-5.12.9 
    && . /usr/share/GNUstep/Makefiles/GNUstep.sh 
    && ./configure && make -j$(nproc) && make install


FROM ubuntu:24.04

RUN apt-get update && apt-get install -y --no-install-recommends 
    gnustep-base-runtime gnustep-base-common libgnustep-base-dev 
    libxml2-dev libpq-dev libssl-dev libcurl4-openssl-dev libmemcached-dev 
    apache2 cron curl sudo ca-certificates tzdata netcat-openbsd

# Copy compiled libs from builder
COPY --from=builder /usr/local/sbin/ /usr/local/sbin/
COPY --from=builder /usr/local/lib/ /usr/local/lib/
RUN ldconfig

# Fix DNS resolution for linked containers
COPY fix_bind.c /tmp/fix_bind.c
RUN gcc -shared -fPIC -o /usr/local/lib/fix_bind.so /tmp/fix_bind.c -ldl

# Enable Apache modules
RUN a2enmod proxy proxy_http rewrite headers expires setenvif

EXPOSE 80
ENTRYPOINT ["/entrypoint.sh"]

3. docker-compose.yml – Der Komplett-Stack

services:
  postgresql:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: sogo
      POSTGRES_PASSWORD: DEIN_SICHERES_PASSWORT
      POSTGRES_DB: sogo
      POSTGRES_INITDB_ARGS: --encoding=UTF8 --locale=en_US.UTF-8
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init-db.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sogo"]
      interval: 10s
      retries: 5
    restart: always

  sogo:
    image: sogo:5.12.9-ubuntu24
    depends_on:
      postgresql: { condition: service_healthy }
    volumes:
      - ./sogo.conf:/etc/sogo/sogo.conf:ro
      - ./apache-sogo.conf:/etc/apache2/sites-enabled/sogo.conf:ro
      - sogo_lib:/var/lib/sogo
      - sogo_log:/var/log/sogo
    ports:
      - "8080:80"
    restart: always
    healthcheck:
      test: ["CMD", "curl", "-f", "http://127.0.0.1:80/SOGo/"]
      interval: 15s
      retries: 5

  memcached:
    image: memcached:alpine
    command: memcached -m 256 -t 4 -c 1024
    restart: always

  sphinx:
    build:
      context: .
      dockerfile: sphinx-build/Dockerfile
    volumes:
      - sphinx_data:/var/lib/sphinx
    ports:
      - "9312:9312"
      - "9306:9306"
    restart: always

volumes:
  postgres_data: {}
  sogo_lib: {}
  sogo_log: {}
  sphinx_data: {}

4. SOGo Konfiguration (sogo.conf)

Die zentrale Konfigurationsdatei. Hier die wichtigsten Abschnitte:

Datenbank (PostgreSQL)

SOGoProfileURL = "postgresql://sogo:DEIN_PASSWORT@postgresql:5432/sogo";
OCSFolderInfoURL = "postgresql://sogo:DEIN_PASSWORT@postgresql:5432/sogo";
OCSSessionsFolderURL = "postgresql://sogo:DEIN_PASSWORT@postgresql:5432/sogo";

Wichtig: Der Connection-String endet auf /sogo (Datenbankname), nicht auf /sogo/table. Letzteres ist ein FATALER Fehler, der zum Crash führt!

IMAP und SMTP

SOGoIMAPServer = "imaps://mail.DEINE-DOMAIN.de:993";
SOGoSMTPServer = "smtp://mail.DEINE-DOMAIN.de:25";
SOGoSieveServer = "sieve://mail.DEINE-DOMAIN.de:4190";
SOGoForceExternalLoginWithEmail = YES;

Memcached und Performance

SOGoMemcachedHost = "memcached:11211";
WOWorkersCount = 10;
SOGoMaximumMessageSizeLimit = 102400;
WOMaxUploadSize = 102400;

ActiveSync (für Smartphones)

SOGoEnableActiveSync = YES;
SOGoMaximumPingInterval = 10;
SOGoMaximumSyncInterval = 30;
SOGoMaximumSyncWindowSize = 100;

Sicherheit

SOGoEncryptionKey = "DEIN_32_ZEICHEN_ZUFALLSSTRING";
SOGoXSRFValidationEnabled = YES;
SOGoEnableCookieSecure = YES;
WOSessionTimeout = 3600;

Generiere den Encryption Key mit: openssl rand -hex 16

Volltextsuche (Sphinx)

SOGoEnableFullTextSearch = YES;
SOGoFullTextSearchServer = "sphinx://sphinx:9306";

Optionale Features

SOGoEnableGroupware = YES;          // Kalender, Kontakte, Aufgaben
SOGoEnableSharedFolders = YES;      // Freigegebene Ordner
SOGoEnableDelegation = YES;         // Rechte delegieren
SOGoEnableEMailReceipts = YES;      // Lesebestätigungen
SOGoEnableTasksSupport = YES;       // Aufgabenverwaltung
SOGoVacationEnabled = YES;          // Abwesenheitsnotizen
SOGoForwardEnabled = YES;           // E-Mail-Weiterleitung
SOGoSieveScriptsEnabled = YES;      // Server-seitige Filter
SOGoMailComposeMessageType = html;  // HTML-E-Mails
SOGoLanguage = German;
SOGoTimeZone = "Europe/Berlin";

5. ISPConfig Integration – User aus MariaDB lesen

SOGo kann sich direkt mit der ISPConfig-Datenbank verbinden und User authentifizieren. Dazu musst du in ISPConfig einen MySQL-User mit Lesezugriff auf die dbispconfig-Datenbank anlegen:

CREATE USER 'sogoread'@'%' IDENTIFIED BY 'DEIN_PASSWORT';
GRANT SELECT ON dbispconfig.* TO 'sogoread'@'%';
FLUSH PRIVILEGES;

In sogo.conf:

SOGoUserSources = (
  {
    type = sql;
    id = users;
    viewURL = "mysql://sogoread:DEIN_PASSWORT@HOST_IP:3306/dbispconfig/sogo_users";
    canAuthenticate = YES;
    isAddressBook = YES;
    userPasswordAlgorithm = "sha512-crypt";
    loginFields = (c_uid);
    mailFieldNames = (c_mail);
    CNFieldName = c_cn;
    UIDFieldName = c_uid;
    displayName = "Benutzer";
  }
);

ISPConfig-Host-Erreichbarkeit: Falls ISPConfig auf dem Docker-Host läuft, verwende host.docker.internal (Docker Desktop) oder die Docker-Gateway-IP 172.17.0.1. Falls ISPConfig in einem anderen Container läuft, verwende den Container-Namen.

6. Apache als interner SOGo-Reverse-Proxy

Innerhalb des Containers läuft Apache als Reverse-Proxy vor SOGo:

<VirtualHost *:80>
    ServerName webmail.DEINE-DOMAIN.de
    ServerAlias webmail.DEINE-ZWEITE-DOMAIN.de

    Alias /SOGo/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/

    <Directory /usr/local/lib/GNUstep/SOGo/>
        AllowOverride None
        Require all granted
    </Directory>

    <Location /SOGo>
        RequestHeader set "x-webobjects-server-port" "443"
        RequestHeader set "x-webobjects-server-name" "%{HOST}e"
        RequestHeader set "x-webobjects-server-url" "https://%{HOST}e"
        RequestHeader unset "x-webobjects-remote-user"
    </Location>

    ProxyPreserveHost On
    ProxyPass /Microsoft-Server-ActiveSync 
        http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync 
        retry=60 connectiontimeout=5 timeout=360
    ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
    ProxyPassReverse /SOGo http://127.0.0.1:20000/SOGo

    # .well-known Redirects für CalDAV und CardDAV
    RewriteEngine On
    RewriteRule ^/.well-known/caldav/?$  /SOGo/dav [R=301]
    RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]

    RedirectMatch ^/$ /SOGo
</VirtualHost>

7. Nginx Reverse Proxy (extern, vor dem Container)

Für SSL-Terminierung und Domain-Verwaltung setzt du einen Nginx-Reverse-Proxy VOR den Docker-Container. Beispiel-Serverblock:

server {
    listen 443 ssl http2;
    server_name webmail.DEINE-DOMAIN.de;

    ssl_certificate     /etc/ssl/DEINE-DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/ssl/DEINE-DOMAIN/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        client_max_body_size 100M;
    }
}

8. Entrypoint-Skript

Das Skript startet Cron, Apache und sogod mit korrekten Umgebungsvariablen:

#!/bin/bash
set -e

# Pfade und Rechte
mkdir -p /var/spool/sogo
chown -R sogo:sogo /var/lib/sogo /var/log/sogo /var/run/sogo
chmod 750 /var/lib/sogo /var/log/sogo /var/run/sogo

# Services starten
service cron start
apachectl start

# LD_LIBRARY_PATH für selbst-kompilierte SOGo-Bibliotheken
export LD_LIBRARY_PATH="/usr/local/lib:/usr/local/lib/sogo:/usr/local/lib/GNUstep"
export LD_PRELOAD="/usr/local/lib/fix_bind.so"

# sogod starten
exec gosu sogo /usr/local/sbin/sogod 
    -WOWorkersCount 10 
    -WOListenQueueSize 500 
    -WOPidFile /var/run/sogo/sogo.pid 
    -WOLogFile /var/log/sogo/sogo.log 
    -WONoDetach YES 
    -WOApplicationBaseURL "https://webmail.DEINE-DOMAIN.de/SOGo" 
    -WOPort 20000 2>&1

Das LD_PRELOAD mit fix_bind.so behebt ein bekanntes DNS-Problem in SOGo-Containern bei der Auflösung anderer Container-Namen.

9. Datenbank-Initialisierung

PostgreSQL wird mit einer init-db.sql gestartet, die die benötigten Tabellen anlegt. SOGo verwaltet seine Tabellen über die OCS*FolderURL-Parameter automatisch. Für ISPConfig-Benutzer brauchst du eine View sogo_users in der dbispconfig-Datenbank:

CREATE VIEW sogo_users AS
  SELECT
    email AS c_uid,
    login AS c_uid,
    CONCAT(vorname, ' ', nachname) AS c_cn,
    email AS c_mail,
    password AS c_password
  FROM mail_user;

10. Bereit bekannte Fehler & Fixes

„PostgreSQL verbindet nicht“

✅ Prüfe, ob das Passwort in beiden Dateien identisch ist: sogo.conf und docker-compose.yml

SOGo startet, aber kein Login möglich

✅ Prüfe die ISPConfig-DB-Erreichbarkeit. Der SOGo-Container muss die MariaDB erreichen können. Teste mit: docker-compose exec sogo nc -zv HOST_IP 3306

„AH00558: Could not reliably determine“ Apache-Warnung

✅ Normal – Apache läuft hinter Nginx. Diese Warnung kann ignoriert werden.

sogod crasht direkt nach Start

✅ Häufigste Ursache: PostgreSQL-URL enthält einen Tabellennamen (z.B. /sogo/sogo_user_profile). Korrekt ist nur der Datenbankname: /sogo

ActiveSync funktioniert nicht

✅ Teste: curl -I https://webmail.DEINE-DOMAIN.de/Microsoft-Server-ActiveSync – sollte HTTP 200 liefern

CalDAV/CardDAV funktioniert nicht

✅ Teste: curl -I https://webmail.DEINE-DOMAIN.de/.well-known/caldav – sollte HTTP 301 Redirect liefern

11. Deployment-Checkliste

  1. sogo.conf mit echten Werten befüllen (Passwörter, Domains, ISPConfig-Host)
  2. docker-compose.yml: POSTGRES_PASSWORD mit sogo.conf abgleichen
  3. SOGoEncryptionKey generieren: openssl rand -hex 16
  4. ISPConfig-View sogo_users in MariaDB anlegen
  5. MySQL-User sogoread mit SELECT-Rechten anlegen
  6. Nginx-Serverblock für SSL + Reverse-Proxy erstellen
  7. docker-compose up -d
  8. docker-compose ps – alle Container healthy?
  9. curl -f https://webmail.DEINE-DOMAIN.de/SOGo/ – HTTP 200?
  10. 🎉 Login mit ISPConfig-Mailadresse testen!

12. Wartung & Monitoring

Täglich prüfen:

docker-compose ps
docker-compose logs sogo --tail 20 | grep ERROR

Wöchentlich:

docker system df                # Speicher-Check
docker-compose logs --tail 200

Monatlich:

docker image prune -a           # Alte Images entfernen
docker volume prune             # Ungenutzte Volumes

Backup:

# PostgreSQL-Dump
docker-compose exec postgresql pg_dump -U sogo sogo > backup.sql

# Volumes sichern
tar -czf volumes-backup.tar.gz /var/lib/docker/volumes/sogo_*

Fazit

Du hast jetzt einen vollständigen Groupware-Server mit Webmail, Kalender, Kontakten, Aufgaben und ActiveSync – komplett unter eigener Kontrolle, auf ARM64, mit ISPConfig-Integration und Docker Compose.

Das Setup funktioniert produktiv mit: Ubuntu 24.04 LTS, SOGo 5.12.9 (Source Build), PostgreSQL 15, Memcached, Apache und Nginx als Reverse-Proxy.

🔗 Weitere Projekte auf GitHub

X

Basti

Entwickler und Smart-Home-Enthusiast aus Deutschland. Ich entwickle Open-Source-Integrationen für Home Assistant (IDM Wärmepumpe, Violet Pool Controller), Modbus-Tools (ModBridge) und betreibe verschiedene Server-Dienste (Matrix, Seafile, SOGo).

GitHub →

Schreibe einen Kommentar