Communication Server
Replace Gmail, Slack, and WhatsApp with self-hosted communication that you fully control. Email, messaging, and video calls — all on your infrastructure, all encrypted, all yours.
This is the most complex TAS recipe. Email in particular has a steep learning curve. But it is also the most impactful — communication autonomy means no one can read, scan, or cut off your conversations.
Goal
Build a communication server that:
- Sends and receives email with your own domain (replacing Gmail / Outlook)
- Provides encrypted team/family messaging (replacing Slack / WhatsApp / Telegram)
- Handles calendar and contacts sync (via Nextcloud, from the Family Cloud recipe)
- Is fully self-hosted — no third-party reading your messages
- Uses proper DNS, DKIM, SPF, and DMARC for email deliverability
Components
| Component | Catalog Card | Role |
|---|---|---|
| Debian | compute/os | Base operating system. VPS or dedicated server with static IP. |
| Stalwart | communication/email | All-in-one email server (SMTP, IMAP, JMAP) |
| Matrix / Element | communication/messaging | Encrypted messaging and calls |
| Caddy | network/proxy | Reverse proxy with automatic HTTPS |
| CrowdSec | security | Protection against email/SSH brute force |
| WireGuard | network/vpn | Secure admin access |
All are A3/T2, except CrowdSec (A2/T2).
Who is this for?
- Small teams or families who want private communication
- Anyone who read Gmail’s privacy policy and decided enough is enough
- Organizations that need to control their email for compliance reasons
- People who already run TAS recipes and want the final piece of autonomy
Estimated setup time: 3–5 hours (email requires DNS configuration and patience). Requirements: A VPS or server with a static IP and port 25 open (many residential ISPs block port 25). A domain name you control.
Important: Self-hosted email is hard. Deliverability depends on IP reputation, DNS records, and proper configuration. If email delivery is critical for your business, consider a hybrid approach: self-host for receiving, use a relay (Mailgun, Amazon SES) for sending, until your IP reputation is established.
Prerequisites
Before starting, you need:
- A domain name (e.g.
example.com) with DNS access - A static public IP with port 25 open (check with your ISP)
- Reverse DNS (PTR record) pointing your IP to
mail.example.com(set via your VPS/ISP) - At least 2 GB RAM and 20 GB disk
Step-by-Step Instructions
1. DNS Records
Set these DNS records before deploying (replace 203.0.113.1 with your IP and example.com with your domain):
| Type | Name | Value | TTL |
|---|---|---|---|
| A | mail.example.com | 203.0.113.1 | 3600 |
| MX | example.com | mail.example.com (priority 10) | 3600 |
| TXT | example.com | v=spf1 a mx ip4:203.0.113.1 -all | 3600 |
| TXT | _dmarc.example.com | v=DMARC1; p=quarantine; rua=mailto:postmaster@example.com | 3600 |
| CNAME | chat.example.com | mail.example.com | 3600 |
| SRV | _matrix._tcp.example.com | 0 10 443 chat.example.com | 3600 |
DKIM record will be generated by Stalwart after deployment — you’ll add it in step 5.
2. Create Project Directory
mkdir -p /opt/communication && cd /opt/communication
3. Create Docker Compose
cat > docker-compose.yml << 'YAMLEOF'
services:
# ── Reverse Proxy ──────────────────────────────────
caddy:
image: caddy:latest
container_name: caddy
ports:
- "80:80"
- "443:443"
volumes:
- ./config/caddy/Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
restart: unless-stopped
# ── Email Server ───────────────────────────────────
stalwart:
image: stalwartlabs/mail-server:latest
container_name: stalwart
ports:
- "25:25"
- "465:465"
- "993:993"
- "4190:4190"
volumes:
- ./data/stalwart:/opt/stalwart-mail
environment:
- STALWART_HOSTNAME=mail.example.com
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
# ── Messaging ──────────────────────────────────────
synapse:
image: matrixdotorg/synapse:latest
container_name: synapse
volumes:
- ./data/synapse:/data
environment:
SYNAPSE_SERVER_NAME: example.com
SYNAPSE_REPORT_STATS: "no"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8008/health"]
interval: 30s
timeout: 5s
retries: 3
element-web:
image: vectorim/element-web:latest
container_name: element
volumes:
- ./config/element/config.json:/app/config.json
restart: unless-stopped
# ── Security ───────────────────────────────────────
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
volumes:
- ./config/crowdsec:/etc/crowdsec
- ./data/crowdsec:/var/lib/crowdsec/data
- /var/log:/var/log:ro
environment:
COLLECTIONS: "crowdsecurity/linux crowdsecurity/postfix"
restart: unless-stopped
volumes:
caddy_data:
YAMLEOF
4. Configure Caddy
mkdir -p config/caddy
cat > config/caddy/Caddyfile << 'EOF'
mail.example.com {
reverse_proxy stalwart:8080
}
chat.example.com {
reverse_proxy element:80
}
chat.example.com/_matrix/* {
reverse_proxy synapse:8008
}
chat.example.com/_synapse/* {
reverse_proxy synapse:8008
}
EOF
5. Deploy and Configure Email
docker compose up -d
Configure Stalwart:
- Open
https://mail.example.com— Stalwart web admin - Create your first email account
- Go to Settings → DKIM — copy the generated DKIM public key
- Add the DKIM TXT record to your DNS:
| Type | Name | Value |
|---|---|---|
| TXT | default._domainkey.example.com | (paste DKIM key from Stalwart) |
- Wait 15–30 minutes for DNS propagation
6. Test Email Deliverability
Send a test email to check-auth@verifier.port25.com — you’ll get an automated reply showing your SPF, DKIM, and DMARC status.
Or use mail-tester.com — aim for a score of 9+/10.
7. Configure Matrix/Element
Generate Synapse config:
docker exec synapse generate
Create config/element/config.json:
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://chat.example.com",
"server_name": "example.com"
}
},
"disable_guests": true,
"disable_3pid_login": false
}
Register your first Matrix user:
docker exec -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml
8. Connect Clients
Email:
- Any email client (Thunderbird, Apple Mail, K-9 Mail)
- IMAP:
mail.example.com:993(SSL) - SMTP:
mail.example.com:465(SSL)
Messaging:
- Open
https://chat.example.comin browser - Or install Element app (iOS, Android, Desktop)
- Log in with your Matrix account
Failure Modes
| Component | Failure scenario | Impact | Recovery |
|---|---|---|---|
| Stalwart | Service crash | Email stops flowing — incoming mail queued by sending servers (typically 24–72 hours) | docker compose restart stalwart. Queued mail will be delivered. |
| Stalwart | Disk full | New mail rejected | Clear old mail, expand storage, restart. |
| Stalwart | IP blacklisted | Outgoing mail rejected by recipients | Check blacklist status at mxtoolbox.com. Request delisting. Consider temporary relay via Mailgun. |
| Synapse | Database corruption | Chat history lost | Restore from backup. Federation means other servers may have copies of federated rooms. |
| Element | Service down | Web UI unavailable | Use any other Matrix client (FluffyChat, Nheko, etc.) — they connect directly to Synapse. |
| Caddy | TLS certificate failure | All services show security warnings | Check Caddy logs. Usually DNS or rate limiting issue. Certificates auto-renew. |
| CrowdSec | False positive | Legitimate email/connections blocked | docker exec crowdsec cscli decisions list and remove the bad decision. |
| DNS | Records misconfigured | Mail delivery fails, chat unreachable | Use dig and nslookup to verify. DNS changes take up to 48 hours. |
Blast radius: Stalwart is the highest-impact component. Email downtime is immediately visible and externally impactful. Monitor it with Uptime Kuma (from Monitoring Stack recipe).
What Replaces What
| Need | You used to use | Now you use | Autonomy gain |
|---|---|---|---|
| Gmail / Outlook | Stalwart | A0 → A3 | |
| Team messaging | Slack / Teams | Matrix / Element | A0 → A3 |
| Video calls | Zoom / Google Meet | Element (Jitsi integration) | A0 → A3 |
| Contact sync | Google Contacts | Stalwart CardDAV or Nextcloud | A0 → A3 |
Honest Warning About Self-Hosted Email
Self-hosted email is the hardest part of digital autonomy. Be prepared for:
- IP reputation: New IPs start with zero reputation. Some providers (Microsoft especially) will reject your mail initially. Building reputation takes weeks of consistent, legitimate sending.
- Maintenance burden: Email servers need monitoring. A misconfigured server can become an open relay. CrowdSec helps, but vigilance is required.
- Deliverability is not guaranteed: Even with perfect SPF/DKIM/DMARC, some providers may filter you. This is the reality of email centralization.
Pragmatic approach: Start by receiving all email on your server (this works immediately). For sending, use a relay service (Mailgun free tier: 100 emails/day) until your IP reputation is established. Gradually shift sending to direct delivery as your reputation grows.
Cost
| Item | One-time | Monthly |
|---|---|---|
| VPS with static IP and port 25 | — | $5–15/month |
| Domain name | — | $1/month |
| Total | — | $6–16/month |
Compare: Google Workspace ($7/user/month) + Slack Pro ($8/user/month) = $15/user/month. For a family of 4: $60/month vs $6–16/month.