nigig-org/nimanyatta/deploy
andodeki fd8b0632ca
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
Include nimanyatta as normal tree (not embedded git)
2026-09-26 09:29:36 +03:00
..
hardening.sh Include nimanyatta as normal tree (not embedded git) 2026-09-26 09:29:36 +03:00
README.md Include nimanyatta as normal tree (not embedded git) 2026-09-26 09:29:36 +03:00
verify-hardening.sh Include nimanyatta as normal tree (not embedded git) 2026-09-26 09:29:36 +03:00

Deployment security workflow

A fresh VPS with a public IP is attacked within hours. This workflow hardens the server before the app is deployed, and re-verifies the state on every deploy.

The two phases

1. One-time hardening (on the fresh VPS)

# From your machine, immediately after first login as root:
ssh root@<vps-ip> 'bash -s' < deploy/hardening.sh

The script refuses to run twice, and performs, in order:

Step What it does
1 Updates system packages, installs ufw, fail2ban, unattended-upgrades
2 Creates a non-root deploy user with sudo privileges
3 Copies your root SSH key to the deploy user
4 Rewrites sshd_config: no root login, no password auth, AllowUsers deploy, MaxAuthTries 4, keeps your SSH port
5 Validates and reloads sshd (does not drop your session)
6 UFW: deny all incoming except SSH + app ports (default 8080)
7 fail2ban: bans 5 failed attempts within 10 min for 1 hour
8 Enables unattended security upgrades

Critical: after the script prints its summary, open a new terminal and test ssh -p 22 deploy@<vps-ip> before closing the root session. Only after that login works should you deploy the app.

2. Verify on every deploy (CI + manual)

Automated (GitHub Actions)

.github/workflows/predeploy-security.yml runs on every push to main / PR and blocks deploy if any job fails:

  • gitleaks – scans for leaked secrets in the repo
  • shellcheck – lints both deploy scripts
  • cargo audit – checks dependencies for known vulnerabilities
  • release build – confirms broadcast_server builds with --features b_server
  • hardening verify – syntax-checks and smoke-runs the verification script

Manual (on the active VPS, any time)

# Audits the live server state; exit 0 = hardened, non-zero = something reverted.
sudo bash deploy/verify-hardening.sh

It prints [PASS]/[FAIL] per check, plus the last 10 unique brute-force usernames from /var/log/auth.log.

Configuration

Both scripts honour environment variables:

DEPLOY_USER=deploy    # the sudo user to create / check
APP_PORTS="8080"      # extra firewall ports (space-separated)
SSH_PORT=22           # your SSH port

Example with custom values:

SSH_PORT=2222 APP_PORTS="8080 9090" ssh root@<vps-ip> 'bash -s' < deploy/hardening.sh

Monitoring (the step you already started)

# Tail for brute-force attempts
sudo tail -f /var/log/auth.log | grep -E 'Failed|Invalid user'

# Watch fail2ban bans
sudo fail2ban-client status sshd

# Blocklist grows here as attackers get banned
sudo cat /etc/fail2ban/jail.local

Order of operations for a new deploy

  1. Provision VPS → get public IP.
  2. ssh root@<ip> 'bash -s' < deploy/hardening.sh (hardening first, before the app).
  3. In a new terminal: ssh deploy@<ip> → confirm it works, then close root session.
  4. Deploy the app binary.
  5. sudo bash deploy/verify-hardening.sh → confirm all [PASS].
  6. Push code → CI re-runs pre-deploy checks automatically.