Black Friday Special

FlyWP Lifetime Deal → Pay Once, Fly Forever

Grab Your Deal
Group 1000005474

Host Stalwart Mail Server on FlyWP with Docker

Running your own email server used to feel like climbing a mountain. With FlyWP, it’s more like taking a pleasant hike with a very good map. Today you’re going to install Stalwart – the modern, all-in-one, open-source mail server written in Rust – on your FlyWP server, even if you’ve never touched Docker Compose before.

Thousands of you asked: “Can I run my own app, not just WordPress or the one-click tools?” The answer is yes, and this guide proves it.

Whether you want to run Stalwart, Ollama, Umami, PocketBase, or any other Dockerized app, the process is the same.

We’ll use the “HTML Site” template as our starting point because it gives you a clean Nginx container with automatic Let’s Encrypt SSL already handled for you.

Let’s go.

Step 1: Create a Static Site in FlyWP

  1. Log into your FlyWP dashboard and go to your desired server.
  2. Click Create New Site → choose HTML.
  3. Use the free FlyWP subdomain or add your own domain.
  4. Enter any name if you’re using test domain (e.g., “stalwart-mail”).
  5. Click Create Site.

FlyWP will spin up an Nginx container, issue a valid SSL certificate, and give you a ready-to-go site. That’s our foundation.

Step 2: Connect via SSH and Stop the Current Containers

Open your terminal and connect to your server (FlyWP shows the exact SSH command in the site overview).

ssh fly@your-server-ip

Once inside, go to your new site folder. Replace the example domain with yours (you’ll see it in the FlyWP dashboard):

cd ~/local-stalwart-xprxqy.flywp.xyz

Stop the running containers so we can edit files safely:

docker compose down

Step 3: Create the Folder for Stalwart Data

Stalwart needs a place to store mail, settings, and the database.

mkdir -p data/stalwart

Step 4: Edit docker-compose.yml – Add the Stalwart Service

Open the docker-compose.yml file with nano or vim:

nano docker-compose.yml

Leave the entire existing nginx service exactly as it is (don’t break SSL!). Scroll to the bottom and add the new stalwart service so the file looks like this:

services:
  nginx:
    image: 'nginxinc/nginx-unprivileged:alpine'
    restart: always
    environment:
      - VIRTUAL_HOST=local-stalwart-xprxqy.flywp.xyz
      - VIRTUAL_PORT=8080
      - CERT_NAME=132/server
      - HTTPS_METHOD=redirect
    user: '1000:1000'
    volumes:
      - './app:/var/www/html'
      - './logs/nginx:/var/log/nginx'
      - './data/nginx/temp:/var/cache/nginx'
      - './data/nginx/cache:/var/run/nginx-cache'
      - './config/nginx/common:/etc/nginx/common'
      - './config/nginx/custom:/etc/nginx/custom'
      - './config/nginx/default.conf:/etc/nginx/conf.d/default.conf'
      - '/home/fly/.fly/nginx/html:/usr/share/nginx/html'
    networks:
      - site-network
      - wordpress-sites

  stalwart:
    image: stalwartlabs/stalwart:latest
    container_name: stalwart
    restart: always
    ports:
      - "25:25"     # SMTP
      - "587:587"   # Submission (STARTTLS)
      - "465:465"   # SMTPS
      - "993:993"   # IMAPS
      - "143:143"   # IMAP
      - "4190:4190" # Sieve (ManageSieve)
    volumes:
      - ./data/stalwart:/opt/stalwart
    networks:
      - site-network

networks:
  site-network:
    name: local-stalwart-xprxqy.flywp.xyz
  wordpress-sites:
    name: wordpress-sites
    external: true

Save and exit (Ctrl+O → Enter → Ctrl+X in nano).

Step 5: Update the Nginx Configuration to Proxy to Stalwart

Stalwart runs its own web interface on port 8080 inside the container. We’ll make Nginx forward all web traffic to it.

Edit the Nginx config:

nano config/nginx/default.conf

Replace everything with this updated version, but make sure the server_name matches your site name:

# FLYWP CONFIG (DON'T REMOVE)
include custom/before/*.conf;

upstream stalwart_http {
    server stalwart:8080;
}

server {
    listen 8080;
    listen [::]:8080;
    server_name local-stalwart-xprxqy.flywp.xyz;

    absolute_redirect off;

    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

    location / {
        proxy_pass http://stalwart_http;
        proxy_http_version 1.1;
        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;
    }

    # FLYWP CONFIG (DON'T REMOVE)
    include custom/server/*.conf;
}

# FLYWP CONFIG (DON'T REMOVE)
include custom/after/*.conf;

Save and exit.

Step 6: Start Everything

docker compose up -d

Wait a few seconds, then check the logs for the magic admin password:

docker compose logs stalwart

You’ll see something like:

stalwart | ✅ Configuration file written to /opt/stalwart/etc/config.toml
stalwart | 🔑 Your administrator account is 'admin' with password 'w95Yuiu36E'.

Copy that password!

Step 7: Log In and Finish Setup

Open your site in the browser and you’ll land on the beautiful Stalwart web admin.
Log in with:

  • Username: admin
  • Password: the one from the logs

Change that password immediately, set up your domain, create accounts, and you’re running your own full-featured mail server with JMAP, IMAP, SMTP, webmail, and anti-spam – all behind FlyWP’s automatic SSL and backups.

That’s It – You Just Deployed a Custom App on FlyWP

From here the sky is the limit.
Want Matomo instead of Google Analytics? Ghost? HedgeDoc? Cal.com?
Just repeat the same pattern:

  1. Start with Static Site → free SSL
  2. Add your service to docker-compose.yml
  3. Point Nginx at it (or expose ports directly if you don’t need the web UI)
  4. docker compose up -d

FlyWP handles the host, backups, updates, firewall, and SSL renewals.
You focus on the app you actually want to run.

Have fun building, and drop a comment below if you get Stalwart (or any other app) running – we love seeing what you create! 🚀

Ready to Break Free?

Stop just running WordPress. Start building your ultimate custom stack.

Click below to explore the documentation and deploy your first custom application, powered by FlyWP’s managed host, SSL, and backups.


Category: Tutorial