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:

  1. A domain name (e.g. example.com) with DNS access
  2. A static public IP with port 25 open (check with your ISP)
  3. Reverse DNS (PTR record) pointing your IP to mail.example.com (set via your VPS/ISP)
  4. 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:

  1. Open https://mail.example.com — Stalwart web admin
  2. Create your first email account
  3. Go to Settings → DKIM — copy the generated DKIM public key
  4. Add the DKIM TXT record to your DNS:
Type Name Value
TXT default._domainkey.example.com (paste DKIM key from Stalwart)
  1. 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.com in 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
Email 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.


This site uses Just the Docs, a documentation theme for Jekyll.