Initial stack: Caddy, Forgejo, Outline, Vaultwarden, Uptime Kuma, n8n
This commit is contained in:
commit
06f8e8812e
6 changed files with 401 additions and 0 deletions
94
HARDENING.md
Normal file
94
HARDENING.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# ~$ Hardening checklist
|
||||
|
||||
This is the non-negotiable baseline before real company data touches the box.
|
||||
Every item is copy-paste ready for Debian/Ubuntu.
|
||||
|
||||
## 1. SSH: keys only, no root
|
||||
|
||||
```bash
|
||||
adduser ops && usermod -aG sudo,docker ops
|
||||
mkdir -p /home/ops/.ssh && cp ~/.ssh/authorized_keys /home/ops/.ssh/ \
|
||||
&& chown -R ops:ops /home/ops/.ssh && chmod 700 /home/ops/.ssh
|
||||
```
|
||||
|
||||
`/etc/ssh/sshd_config.d/hardening.conf`:
|
||||
|
||||
```
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl restart ssh
|
||||
# TEST A NEW SSH SESSION BEFORE CLOSING THIS ONE.
|
||||
```
|
||||
|
||||
## 2. Firewall — four ports, nothing else
|
||||
|
||||
```bash
|
||||
apt install -y ufw
|
||||
ufw default deny incoming
|
||||
ufw allow 80/tcp 443/tcp 443/udp # caddy (http/https/h3)
|
||||
ufw allow 2222/tcp # git ssh
|
||||
ufw allow 51820/udp # wireguard (only if using --profile vpn)
|
||||
ufw allow 22/tcp # your ssh (move it if you want)
|
||||
ufw enable
|
||||
```
|
||||
|
||||
Note: Docker's published ports bypass ufw INPUT rules — that's exactly why this
|
||||
compose file publishes only caddy, git-ssh and wireguard, and keeps postgres/redis
|
||||
on the `internal` network with no ports at all. Don't add `ports:` to internal
|
||||
services "for debugging" and forget them.
|
||||
|
||||
## 3. Automatic security updates
|
||||
|
||||
```bash
|
||||
apt install -y unattended-upgrades
|
||||
dpkg-reconfigure -plow unattended-upgrades
|
||||
```
|
||||
|
||||
## 4. fail2ban (ssh brute force)
|
||||
|
||||
```bash
|
||||
apt install -y fail2ban # default ssh jail is enough to start
|
||||
```
|
||||
|
||||
## 5. Vaultwarden specifics
|
||||
|
||||
- `VAULTWARDEN_SIGNUPS_ALLOWED=false` the moment your team is on board.
|
||||
- Use an argon2 `ADMIN_TOKEN` (`vaultwarden hash` / see wiki), not a plain string.
|
||||
- The admin panel (`/admin`) is for setup — consider blocking it in Caddy afterwards:
|
||||
|
||||
```
|
||||
vault.{$DOMAIN} {
|
||||
@admin path /admin*
|
||||
respond @admin 404
|
||||
reverse_proxy vaultwarden:80
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Pin your images
|
||||
|
||||
`latest` is fine on day one, dangerous on day 300. Pin majors at minimum
|
||||
(`caddy:2-alpine`, `forgejo:11`, `uptime-kuma:1` already are). Watchtower blindly
|
||||
auto-updating a password manager at 3 a.m. is how you get incidents — update
|
||||
deliberately: `docker compose pull && docker compose up -d` after reading release notes.
|
||||
n8n and Outline move fast; Vaultwarden occasionally has breaking web-vault pairs.
|
||||
|
||||
## 7. Backups (minimum viable, today)
|
||||
|
||||
```bash
|
||||
# stop, snapshot volumes, start — cron it nightly until Episode 10 (borgmatic offsite)
|
||||
docker compose stop
|
||||
tar czf /backup/stack-$(date +%F).tgz -C /var/lib/docker/volumes .
|
||||
docker compose start
|
||||
```
|
||||
|
||||
Plus: enable your provider's server snapshots. Two clicks, saves your company.
|
||||
|
||||
## 8. What this list is NOT
|
||||
|
||||
Not covered here, on purpose (own episodes): SSO everywhere, 2FA enforcement
|
||||
per service, Netbird zero-trust mesh, central logging, CrowdSec, offsite borg.
|
||||
Baseline first. Perfect later.
|
||||
Loading…
Add table
Add a link
Reference in a new issue