7faa9098de
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
251 lines
7.6 KiB
Markdown
251 lines
7.6 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```yaml
|
|
#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
|
|
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
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
|
|
```bash
|
|
# Test SSH config
|
|
sshd -t
|
|
|
|
# View SSH attempts
|
|
journalctl -u sshd -f
|
|
|
|
# Check sshguard blocks
|
|
iptables -L sshguard -n
|
|
```
|
|
|
|
### Firewall Issues
|
|
```bash
|
|
awall list # Show firewall policies
|
|
awall translate # Test policy compilation
|
|
iptables -L -n # Show active rules
|
|
```
|
|
|
|
### Certificate Issues
|
|
```bash
|
|
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.
|