# VPS Setup
Checklist for setting up a fresh VPS.
## Initial Access and User Setup
Create a regular user, add them to `sudo`, and disable root login over SSH:
```bash
adduser deploy
usermod -aG sudo deploy
```
Set up SSH key authentication for the new user before disabling password auth. Copy your public key into `~/.ssh/authorized_keys` (or use `ssh-copy-id`). Then in `/etc/ssh/sshd_config`:
```text
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
```
Restart `sshd` — but keep your current session open until you've confirmed you can log in with the new user in a second terminal. Locking yourself out of a VPS is not fun.
## Firewall
Set up `ufw` (or `nftables`/`iptables` directly) early:
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw enable
```
Only open ports you actually need (80, 443, etc.) as you go.
## SSH Hardening
Beyond disabling passwords and root login, consider:
- Changing the default SSH port (minor but reduces log noise from bots)
- Setting `MaxAuthTries 3`
- Using `AllowUsers deploy` to explicitly whitelist who can log in
- Installing `fail2ban` to auto-ban IPs after repeated failed attempts
See also: [[SSH]]
## System Updates
```bash
apt update && apt upgrade -y
```
Enable unattended security updates (`unattended-upgrades` on Debian/Ubuntu) so critical patches get applied automatically. Configure it to only auto-apply security updates and notify you about the rest.
## Other Security Considerations
- **Disable unused services** — check what's listening with `ss -tlnp` and stop/remove anything you don't need
- **Set up a swap file** if your VPS has limited RAM, otherwise OOM kills can take down your services unexpectedly
- **Configure timezone and locale** — `timedatectl set-timezone Europe/Zurich` (or wherever makes sense), keeps logs readable
- **Log monitoring** — at minimum, know where your logs are. `journalctl` for systemd services, `/var/log/auth.log` for login attempts. Tools like `logwatch` can send you daily summaries
- **Automatic reboots** after kernel updates — `needrestart` helps you see what needs restarting, or set up automatic reboot via cron
## Running Web Services
- Use a reverse proxy (nginx/Caddy) — Caddy is especially nice because it handles TLS certificates automatically
- Don't run application processes as root. Create dedicated service users with minimal permissions
- Use [[Docker]] if it fits your workflow, but be aware that Docker by default punches through `ufw` rules. Configure Docker's iptables behavior or use `docker-compose` network settings carefully
## Backups
Set up automated backups from day one, even if it's just a cron job rsyncing to another location or using your provider's snapshot feature. Test restoring at least once.
## Optional
- **2FA for SSH** via `libpam-google-authenticator`
- **AppArmor or SELinux** profiles for services you expose publicly
- **Monitoring** — `htop`/`btop` for interactive use, Prometheus + node_exporter or a simple uptime check (UptimeRobot, etc.) for ongoing visibility
The general principle: minimal attack surface, least privilege, and assume someone will try to break in — automated scanners hit new VPS IPs within minutes.
---
See also: [[Linux]], [[SSH]], [[Docker]]