Upgrading high-availability Stalwart cluster

High-Availability Stalwart Upgrading
High-Availability Stalwart Upgrading

Introduction

Following my article from last November on deploying high-availability Stalwart for production, I'm following up today with a step-by-step guide on how to upgrade your cluster effectively.

Prerequisites

  1. An existing High-Availability (HA) Stalwart cluster.

Step-by-step

This guide assumes a deployment of two Stalwart servers running via Docker and covers the upgrade process to version 0.15.5.

  1. Gracefully shut down one of the Stalwart instances (Server 1) before proceeding with the upgrade

    docker compose down
    
  2. On the second Stalwart server (Server 2), edit the docker-compose.yml file to update the image tag to version 0.15.5.

    ...
    stalwart:
      image: stalwartlabs/stalwart:v0.15.5
    ...  
    
  3. Pull the updated Stalwart image version.

    docker compose pull
    [+] Pulling 9/9
    ✔ tlsa Pulled                                                                                                                                                                                                           0.4s 
    ✔ stalwart Pulled                                                                                                                                                                                                       4.0s 
      ✔ 807c805f87bc Pull complete                                                                                                                                                                                          1.8s 
      ✔ 7b58964aea23 Pull complete                                                                                                                                                                                          1.8s 
      ✔ beaddcc88480 Pull complete                                                                                                                                                                                          2.1s 
      ✔ 39c80da22d92 Pull complete                                                                                                                                                                                          2.5s 
      ✔ 55c39da61968 Pull complete                                                                                                                                                                                          2.6s 
      ✔ 34b55b24ec56 Pull complete                                                                                                                                                                                          2.6s 
      ✔ 2e3fc8c6d8c1 Pull complete           
    
  4. Restart the Stalwart container to apply the new version.

    docker compose down && docker compose up -d
    [+] Running 3/3
    ✔ Container stalwart       Removed                                                                                                                                                                                      1.6s 
    ✔ Container tlsa           Removed                                                                                                                                                                                     10.2s 
    ✔ Network stalwart_ip6net  Removed                                                                                                                                                                                      0.2s 
    [+] Running 3/3
    ✔ Network stalwart_ip6net  Created                                                                                                                                                                                      0.1s 
    ✔ Container stalwart       Started                                                                                                                                                                                      0.4s 
    ✔ Container tlsa           Started
    
  5. Verify that the service is running the correct version by inspecting the container logs.

    cat data/logs/stalwart.log.2026-03-15
    
    2026-03-15T15:08:16Z INFO Starting Stalwart Server v0.15.5 (server.startup) version = "0.15.5"
    2026-03-15T15:08:16Z INFO Downloading external resource (resource.download-external) details = "Downloaded ASN/Geo data", url = "https://cdn.jsdelivr.net/npm/@ip-location-db/asn/asn-ipv4.csv", elapsed = 230ms
    2026-03-15T15:08:16Z INFO Downloading external resource (resource.download-external) details = "Downloaded ASN/Geo data", url = "https://cdn.jsdelivr.net/npm/@ip-location-db/asn/asn-ipv6.csv", elapsed = 101ms
    2026-03-15T15:08:17Z INFO Webadmin resource unpacked (resource.webadmin-unpacked) path = "/tmp/STALWART_WEBADMIN"
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "http", localIp = ::, localPort = 8080, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "https", localIp = ::, localPort = 443, tls = true
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "imap", localIp = ::, localPort = 143, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "imaptls", localIp = ::, localPort = 993, tls = true
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "pop3", localIp = ::, localPort = 110, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "pop3s", localIp = ::, localPort = 995, tls = true
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "sieve", localIp = ::, localPort = 4190, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "smtp", localIp = ::, localPort = 25, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "submission", localIp = ::, localPort = 587, tls = false
    2026-03-15T15:08:17Z INFO Network listener started (network.listen-start) listenerId = "submissions", localIp = ::, localPort = 465, tls = true
    
  6. To upgrade the Webadmin, navigate to the UI and select Manage > Maintenance > Update Webadmin.

  7. Return to Server 1 and update the docker-compose.yml file with the new version tag.

  8. Repeat the previous 'pull' and 'restart' steps for Server 1

    docker compose pull
    docker compose down && docker compose up -d
    
  9. As a final step, inspect the logs on Server 1 to verify that it is running the correct version.

    cat data/logs/stalwart.log.2026-03-15
    
    2026-03-15T15:08:16Z INFO Starting Stalwart Server v0.15.5 (server.startup) version = "0.15.5"
    

Conclusion

Congratulations! You have successfully upgraded your HA Stalwart cluster for production. Your system is now ready for secure email delivery. Happy sending!

References

If you found this useful, you can buy me a coffee! Thanks for the support!