Skip to content

Updating and Hardening

Blake Foley edited this page Sep 17, 2026 · 1 revision

Updating and Hardening

update.sh

sudo deploy/update.sh

Wraps scripts/update_cli.php: pulls application code updates, then runs any pending database migrations from admin/database_updates.php up to includes/database_version.php's LATEST_DATABASE_VERSION.

Recommended cadence: monthly, or right after harden.sh's unattended-upgrades has kept the OS current but a known application-level fix has shipped. Always take a fresh Backup and Restore run (or confirm the scheduled timer ran recently) before updating a production instance — a schema migration is exactly the kind of change you want a tested rollback path for.

Deliberately uses plain --update (a git pull), never --force_update (git fetch --all && git reset --hard origin/master) — a hard reset in an automated wrapper would silently discard any local edit made directly on the box, which a git pull instead merges or fails loudly on.

harden.sh

sudo deploy/harden.sh                    # box-wide hardening only
sudo deploy/harden.sh --dry-run          # preview every action, change nothing
sudo deploy/harden.sh --domain itflow.example.com --app-root /var/www/itflow.example.com \
    --ssl-cert /etc/ssl/certs/itflow.example.com.crt \
    --ssl-cert-key /etc/ssl/private/itflow.example.com.key
                                          # also (re)render that vhost hardened

A standalone, idempotent, re-runnable hardening pass — the fuller superset of what Bare Metal Install's install.sh applies inline during a fresh install.

What it applies

  1. PHP-FPM hardening — validated with a config test, service reloaded only on success, rolled back automatically otherwise.
  2. MariaDB hardening — same validate-then-restart-then-rollback pattern.
  3. A mysql_secure_installation-equivalent cleanup — removes anonymous MySQL users and the test database (skipped, with a warning, if MariaDB's root account isn't using the default unix_socket auth this expects).
  4. fail2ban jails for SSH brute-force and repeated failed/blocked app auth requests.
  5. ufw — auto-detects every port sshd actually listens on and allows all of them, plus 80/443 (and 8443 in --proxy-mode), before enabling the firewall.
  6. unattended-upgrades, restricted to -security origin packages only, with automatic reboot explicitly disabled (a live app rebooting itself unattended is its own outage).
  7. nginx — the shared rate-limit zone and shared locations snippet unconditionally, plus (only if --domain/--app-root/--ssl-cert/--ssl-cert-key are given) a re-rendered vhost for that domain.

Every step is check-before-act and safe to run repeatedly — including against a box that already has one or more other ITFlow instances hardened by an earlier run.

Standalone vs. letting install.sh call it

install.sh does not invoke harden.sh. It applies its own inline copy of steps 1–2 and 4–5 above during a fresh install, but not the mysql_secure_installation cleanup (3) or unattended-upgrades (6). Practical recommendation: run harden.sh once, standalone, right after install.sh completes —

sudo deploy/install.sh --domain=itflow.example.com ...
sudo deploy/harden.sh

— it'll find the config install.sh already applied unchanged and skip re-writing it, so you only actually pick up the two extra steps.

harden.sh is also the right tool, entirely on its own, for a company that already has ITFlow running from a manual or older setup and just wants to retrofit this hardening onto it. Always preview first with --dry-run on a box you didn't just build with install.sh.

Selective skips are available for every section (--skip-php, --skip-mariadb, --skip-mysql-secure, --skip-fail2ban, --skip-ufw, --skip-unattended-upgrades, --skip-nginx) — see --help for the full list.

Clone this wiki locally