logo
NotesNotesResumeResume
© 2026 Kiet Nguyen
← Projects
2026ToolchainComplete

Automated Server Setup

One-command Ubuntu/Debian host bootstrap—restricted service user, key-only SSH, minimal firewall, nginx, hardening drop-ins, and a pass/fail self-check report.

Stack·Bash · Ubuntu · OpenSSH · ufw · nginx · Multipass · Docker/Colima

Signals·Idempotent Bash bootstrap · SSH harden · ufw · nginx · self-check

Requirements outline

Scope this page covers. Each row is an acceptance item the automation targets; delivery is what ships in this revision.

IDRequirementDelivery
FR1Restricted non-root service userappsvc system account, /var/lib/appsvc (0750), shell nologin, password locked
FR2SSH hardened (keys only)sshd drop-in — no password auth, no root login, PubkeyAuthentication yes, AllowUsers admin
FR3Minimal host firewallufw default deny incoming; allow OpenSSH + 80/tcp only
FR4Real service installed and runningnginx enabled under systemd; static site on port 80
FR5Basic system hardeningunattended-upgrades, sysctl drop-in, SSH banner, PermitEmptyPasswords no, sudo membership hygiene
FR6Automation self-checkPASS/FAIL report per FR; non-zero exit if any check fails

Evidence

Terminal capture of Multipass self-check with all PASS lines and RESULT ALL CHECKS PASSED
Self-check — Multipass ass-lab (Ubuntu 24.04)
Terminal capture of sshd -T hardening flags and ufw active allow rules
Independent verify — sshd -T · ufw status
Terminal capture of getent passwd appsvc showing nologin shell and service home
FR1 — appsvc service user
Terminal capture of systemctl is-active nginx and curl HTML response
FR4 — nginx active · HTTP 200 path

Terminal captures from the lab host. Click an image to expand fullscreen.

Problem

I wanted a single, re-runnable automation for a clean Ubuntu/Debian box: bring the host from a minimal install to a known baseline without mid-run manual steps, and finish with explicit verification rather than treating a quiet command exit as success. The failure modes I designed around include SSH lockout (password auth off without keys) and firewall order (default deny before an SSH allow rule).

Approach

setup.sh sources modular stages (lib/01–06): system user appsvc with nologin and locked password; sshd drop-in (PasswordAuthentication no, PermitRootLogin no, AllowUsers admin); ufw default deny with OpenSSH + port 80 only; nginx serving a static proof page; unattended-upgrades and sysctl hardening; then a self-check that writes PASS/FAIL lines to /var/log/automated-server-setup-selfcheck.txt and exits non-zero on any fail. File writes are cmp-idempotent; packages install only when missing. Validated on Multipass Ubuntu 24.04 (systemd) twice, plus a Docker/Colima privileged smoke run.

Outcomes

  • Self-check ALL CHECKS PASSED on Multipass Ubuntu 24.04 (ass-lab), including systemd nginx
  • Second run on the same VM also ALL CHECKS PASSED (idempotent path exercised)
  • Independent probes recorded (sshd -T, ufw status, getent appsvc, curl localhost)
  • Docker/Colima smoke path green for packages/config (no full systemd claim there)
  • Mitigations encoded (keys before password-off; allow SSH before ufw enable; sshd -t before reload)

Status is honest: Study and In progress mean the work is not overclaimed as production-complete.

Back to project index