Files
57_Wolve 7faa9098de feat: unified launcher, multi-OS hardening, login alerts & auto-updates
Restructure around a single entry point (automations.sh) with a Gum wizard and
a self-extracting bundle for repo-less installs. Add scripts/oslib.sh so the
provisioning scripts (setup-host, harden-ssh, harden-jumphost, sshuser) run on
Alpine/Debian/Alma; seed root keys from globals/.

- ntfy SSH-login alerts (user, source IP, key, region, jump target) via pam_exec
- daily auto-updates with AUTO_REBOOT=idle (reboots only when no SSH active) and
  opt-in Alpine stable-branch upgrades
- generic + per-deployment cloud-init; Gitea release workflow on tag
- README/LICENSE/.gitignore/.gitattributes (force LF); repo URLs -> Gitea
2026-06-12 14:56:02 -05:00
..

SimpleX Relay Server Deployment

Complete automated deployment for SimpleX Chat relay servers on Alpine Linux with post-quantum SSH hardening, Tor hidden services, and encrypted backups.

Quick Start

1. Clone This Repository

The installer fetches its scripts straight from this monorepo's layout:

automations/
├── scripts/
│   └── harden-ssh.sh          # generic SSH hardening (PQ KEX + Ed25519)
├── deployments/simplex/
│   ├── deploy-simplex.sh      # SMP + XFTP + Tor deployment
│   ├── backup.sh              # age-encrypted backup creation
│   ├── restore.sh             # disaster recovery from backup
│   ├── install-simplex.sh     # master installer (cloud-init compatible)
│   ├── cloud-init.yml         # example cloud-init configuration
│   └── README.md              # this file
└── globals/
    └── age-pubkey.txt         # your age public key(s) for backups

Point REPO_URL at your fork of this repo. The installer resolves harden-ssh.sh under scripts/ and the simplex scripts under deployments/simplex/ automatically (overridable via HARDEN_PATH / SIMPLEX_PATH).

2. Generate Backup Keys

# Generate age keypair for backups
age-keygen -o backup-private-key.txt

# Save the public key to the shared globals/ folder
echo "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p" > globals/age-pubkey.txt

# Store the private key securely (NOT in your repo)
cp backup-private-key.txt ~/safe-location/

3. Deploy via Cloud-Init

Create a cloud instance with this user-data:

#cloud-config
runcmd:
  - |
    curl -fsSL https://git.anomalous.dev/57_Wolve/automations/raw/branch/main/deployments/simplex/install-simplex.sh | \
    REPO_URL=https://git.anomalous.dev/57_Wolve/automations.git \
    DOMAIN=relay.example.com \
    ACME_EMAIL=admin@example.com \
    XFTP_QUOTA=100gb \
    SSH_PORT=2222 \
    ALLOWED_IP=1.2.3.4 \
    bash

4. Manual Deployment

# On a fresh Alpine Linux host:
curl -fsSL https://git.anomalous.dev/57_Wolve/automations/raw/branch/main/deployments/simplex/install-simplex.sh | \
REPO_URL=https://git.anomalous.dev/57_Wolve/automations.git \
DOMAIN=relay.example.com \
ACME_EMAIL=admin@example.com \
XFTP_QUOTA=50gb \
SSH_PORT=2222 \
bash

Configuration Options

Variable Required Default Description
REPO_URL Git repository URL containing deployment scripts
DOMAIN Apex domain (creates smp.DOMAIN, xftp.DOMAIN)
ACME_EMAIL Email for Let's Encrypt registration
XFTP_QUOTA 50gb Disk quota for file storage
SSH_PORT 22 SSH port (recommend changing from default)
ALLOWED_IP Your IP to whitelist in sshguard
KEY_TYPE rsa4096 Caddy TLS key type (rsa4096, p384, ed25519)
SMP_PASS Optional password for SMP queue creation
XFTP_PASS Optional password for XFTP uploads
SKIP_PROMPTS 0 Set to 1 for non-interactive installation

What Gets Deployed

Security Features

  • Post-quantum SSH: Hybrid KEX (mlkem768x25519, sntrup761x25519) + Ed25519 keys
  • Minimal attack surface: Only SSH terminal + SFTP, no forwarding/tunnels
  • Firewall: awall with explicit allow-list for required ports only
  • Brute-force protection: sshguard with progressive IP bans

SimpleX Infrastructure

  • SMP server: Message relay on port 5223
  • XFTP server: File transfer on port 5443
  • Tor hidden services: .onion addresses for both servers
  • TLS termination: Caddy with Let's Encrypt and strong crypto
  • Docker compose: Orchestrated deployment with health checks

Operational Features

  • Encrypted backups: All private keys backed up with age encryption
  • CA key removal: Private keys removed from disk after backup
  • Service monitoring: OpenRC integration with auto-restart
  • Address discovery: Scripts to show server fingerprints and .onion URLs

Server Addresses

After deployment, your relay will be accessible at:

# Clearnet
smp://FINGERPRINT@smp.yourdomain.com
xftp://FINGERPRINT@xftp.yourdomain.com

# Tor (clients with Orbot/Tor)
smp://FINGERPRINT@smp.yourdomain.com,ONIONADDRESS.onion
xftp://FINGERPRINT@xftp.yourdomain.com,ONIONADDRESS.onion

Get the full addresses with: cd /opt/simplex && ./print-addresses.sh

Backup & Recovery

Creating Backups

# Manual backup (on the server)
AGE_RECIPIENT_FILE=/path/to/age-pubkey.txt bash backup.sh

# Or with a single recipient
AGE_RECIPIENT=age1ql3z7... bash backup.sh

Disaster Recovery

# 1. Fresh Alpine install
# 2. Upload restore script and backup
scp restore.sh backup-20250101-120000.tar.gz.age root@new-host:/root/

# 3. Restore (preserves all server identities)
ssh root@new-host
bash restore.sh backup-20250101-120000.tar.gz.age

# 4. Update DNS to point at new host

DNS Configuration

Create these DNS records before deployment:

smp.yourdomain.com.  300 IN A    1.2.3.4
xftp.yourdomain.com. 300 IN A    1.2.3.4

Replace 1.2.3.4 with your server's IP address.

Architecture

Internet
    ↓
[Caddy :80,:443] ← Let's Encrypt ACME
    ↓
[Docker Network]
    ├─ [SMP Server :5223] ← Tor Hidden Service
    └─ [XFTP Server :5443] ← Tor Hidden Service
  • Ports 80/443: Caddy (HTTP redirect + ACME + info pages)
  • Port 5223: SMP protocol (TCP, server's own TLS)
  • Port 5443: XFTP protocol (TCP, server's own TLS)
  • Port 22/2222: SSH (PQ KEX + Ed25519 only)

File Locations

  • Deployment: /opt/simplex/ (docker-compose.yml, configs, scripts)
  • Server keys: /opt/simplex/{smp,xftp}_configs/ (CA keys removed after backup)
  • Tor keys: /opt/simplex/{smp,xftp}_tor/ (hidden service identity)
  • SSH config: /etc/ssh/ (hardened sshd_config + Ed25519 host key)
  • Firewall: /etc/awall/optional/ (JSON policy files)
  • Backups: /tmp/simplex-backup-YYYYMMDD-HHMMSS.tar.gz.age

Security Notes

What's Quantum-Safe

  • Session keys: PQ hybrid KEX protects against "store now, decrypt later"
  • Authentication: Ed25519 keys (classical, but strongest practical choice today)

Network Hardening

  • Only required ports open (22/2222, 80, 443, 5223, 5443)
  • SSH locked to key-only auth, no forwarding, rate-limited
  • sshguard blocks brute-force attempts with progressive delays

Key Management

  • CA private keys backed up encrypted, then removed from disk
  • Tor onion keys preserved for stable .onion addresses
  • SSH host key preserved for stable fingerprint
  • All backups encrypted with age (modern, simple, secure)

Troubleshooting

Check Service Status

cd /opt/simplex
docker compose ps                    # Container status
docker compose logs -f smp-server   # SMP logs  
docker compose logs -f xftp-server  # XFTP logs
./print-addresses.sh                # Show server addresses

SSH Issues

# Test SSH config
sshd -t

# View SSH attempts
journalctl -u sshd -f

# Check sshguard blocks
iptables -L sshguard -n

Firewall Issues

awall list                          # Show firewall policies
awall translate                     # Test policy compilation
iptables -L -n                      # Show active rules

Certificate Issues

docker exec simplex-caddy caddy list-certificates
docker logs simplex-caddy

Contributing

  1. Fork this repository
  2. Make your changes
  3. Test on a fresh Alpine instance
  4. Submit a pull request

License

This deployment is provided as-is for educational and operational use. The SimpleX Chat software itself is licensed under AGPL-3.0.