A growing collection of server automation scripts β UFW backup, port scanning, Caddy install/update, Docker setup, and more. Designed for quick, idempotent VPS provisioning and maintenance.
| Script | What it does | Safe to re-run |
|---|---|---|
ufw_backups.sh |
Backup, restore, list, and manage UFW firewall rulesets | β |
port_scanner.sh |
Scan exposed ports, assess risk, close ports via UFW, identify listening processes | β |
setup_docker.sh |
Install Docker Engine from the official repo, optional build tooling | β |
caddy/setup_caddy.sh |
Build and install Caddy with Cloudflare DNS plugin, systemd service, hardened permissions | β |
caddy/update_caddy.sh |
Rebuild latest Caddy, atomic binary swap, zero-downtime reload | β |
git clone https://github.com/danielperez9430/server-toolkit.git
cd server-toolkit
# Audit your firewall and ports
sudo bash ufw_backups.sh
sudo bash port_scanner.sh
# Set up Docker + Caddy on a fresh VPS
sudo bash setup_docker.sh --build
bash caddy/setup_caddy.shAll scripts auto-detect Debian or Ubuntu. They install missing dependencies and skip work that's already done β so you can run them again without breaking anything.
ufw_backups.sh β interactive menu for managing your UFW firewall rules.
Menu options:
| # | Action | Details |
|---|---|---|
| 1 | Create backup | Timestamped .tar.gz of all .rules files + ufw.conf + human-readable ufw status verbose |
| 2 | Restore backup | Pick from a list of saved backups. Creates a safety snapshot of current rules before overwriting, then reloads UFW |
| 3 | List backups | Browse all stored backups with file sizes |
| 4 | View live rules | Runs ufw status verbose in one keystroke |
| 5 | Delete backup | Clean up old snapshots |
Backups are stored under $HOME/ufw_backups/. The restore flow is deliberately cautious β it snapshots your current rules before touching anything, so you can always undo.
sudo bash ufw_backups.shport_scanner.sh β interactive port audit with risk classification.
Menu options:
| # | Action | Details |
|---|---|---|
| 1 | Scan exposed ports | Lists every port listening on 0.0.0.0 or :: (publicly reachable), annotated with service name and risk level |
| 2 | Close an exposed port | Blocks a selected port via ufw deny. Only shows ports you can actually close |
| 3 | View all ports | Full ss -tulnp dump, color-coded: cyan for exposed, dim for localhost-only |
| 4 | Find process by port | Cross-references ss and lsof to tell you exactly what's listening |
| 5 | Risk summary | Tally of low / medium / high risk ports with a verdict |
Risk classification:
| Level | Ports | Signal |
|---|---|---|
| π’ Low | 80, 443 | Web traffic β expected |
| π‘ Medium | 22 | SSH β review key-only auth |
| π΄ High | Everything else | Likely unintended exposure β close it |
Common ports get named automatically (MySQL β 3306, Redis β 6379, Postgres β 5432, MongoDB β 27017, Elasticsearch β 9200, RabbitMQ β 5672, and more).
sudo bash port_scanner.shsetup_docker.sh β installs Docker Engine from the official Docker repository. Runs the full documented flow: purge old packages, add the GPG key, configure the apt source, install, enable the systemd unit, and optionally add your user to the docker group.
Flags:
| Flag | Effect |
|---|---|
| (none) | Runtime only β docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin |
--build |
Runtime + build tooling β adds docker-buildx-plugin |
After installation, the script drops you into a fresh login shell so the docker group change takes effect immediately β no need to log out and back in.
sudo bash setup_docker.sh # runtime only
sudo bash setup_docker.sh --build # runtime + buildx for image buildscaddy/setup_caddy.sh β builds Caddy from source via xcaddy with the Cloudflare DNS provider plugin baked in. This is the path you want when serving sites behind Cloudflare β DNS-01 challenges mean Caddy can obtain TLS certificates without opening port 80/443 to the world during validation.
What it does:
- Installs
xcaddyfrom the Cloudsmith repo - Builds Caddy with
--with github.com/caddy-dns/cloudflare - Creates a locked-down
caddysystem user (/usr/sbin/nologin, no shell access) - Writes
/etc/caddy/,/var/lib/caddy/,/var/log/caddy/with tight permissions (750) - Deploys a hardened systemd unit β
ProtectSystem=full,PrivateTmp=true, no extra capabilities beyondCAP_NET_BIND_SERVICE - Enables the service but does not start it β you control when Caddy goes live
The service is not started automatically. You edit your Caddyfile first, then start it yourself.
bash caddy/setup_caddy.shNext steps after setup:
sudo nano /etc/caddy/Caddyfile # add your domains + CF_API_TOKEN
sudo systemctl start caddy # go live
sudo systemctl status caddy # confirm
sudo journalctl -u caddy -f # tail logscaddy/update_caddy.sh β fetches the latest Caddy release tag from GitHub, compares it to your installed version, rebuilds with the same plugin set, and swaps the binary in place.
Safety guarantees:
- Pre-update backup β current binary copied to
/usr/local/bin/caddy.bakbefore the swap - Validation gate β new binary is run with
caddy versionbefore it replaces the old one. If the build is broken, the script aborts and leaves your existing installation untouched - Atomic swap β uses
mv(same filesystem, so it's a rename β not a copy) to replace the running binary - Zero-downtime reload β sends
systemctl reload caddyif the service is active. Falls back to a full restart if reload fails - Temp directory cleanup β build artifacts land in
mktemp -d, cleaned up on exit viatrap
If the running version already matches the latest tag, the script exits cleanly.
sudo bash caddy/update_caddy.shRollback (if needed):
sudo systemctl stop caddy
sudo cp /usr/local/bin/caddy.bak /usr/local/bin/caddy
sudo systemctl start caddyserver-toolkit/
βββ ufw_backups.sh # UFW backup & restore
βββ port_scanner.sh # Port audit & risk assessment
βββ setup_docker.sh # Docker Engine installer
βββ caddy/
β βββ setup_caddy.sh # Caddy + Cloudflare DNS plugin installer
β βββ update_caddy.sh # Caddy updater (atomic swap)
βββ LICENSE # MIT
βββ README.md
| Principle | What it means in practice |
|---|---|
| Idempotent | Scripts check current state before acting. Re-running setup_docker.sh won't break an existing install. Re-running update_caddy.sh exits early if you're already on the latest version |
| Safe by default | Destructive operations are guarded. ufw_backups.sh snapshots your live rules before restoring. update_caddy.sh backs up the binary before swapping. setup_docker.sh drops into a login shell so group membership takes effect cleanly |
| Composable | Each script does one thing. Chain them together for provisioning. Use them individually for maintenance |
| Interactive + scriptable | Menu-driven scripts (ufw_backups.sh, port_scanner.sh) expose every action through numbered menus. Flag-driven scripts (setup_docker.sh, update_caddy.sh) work in pipelines |
- OS: Debian or Ubuntu (uses
aptanddpkg) - Privileges:
sudoor root for most scripts - Network: outbound internet access to fetch packages and GPG keys
- Shell: Bash 4+
MIT β see LICENSE.
Built for quick, repeatable VPS provisioning. PRs welcome for additional scripts that fit the philosophy.