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
- Log into your FlyWP dashboard and go to your desired server.
- Click Create New Site → choose HTML.
- Use the free FlyWP subdomain or add your own domain.
- Enter any name if you’re using test domain (e.g., “stalwart-mail”).
- 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:
- Start with Static Site → free SSL
- Add your service to docker-compose.yml
- Point Nginx at it (or expose ports directly if you don’t need the web UI)
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.
