Skip to content
mh-sudoPublic

About

Vps Forge — interactive TUI that takes a fresh Ubuntu VPS to production-ready in minutes: SSH hardening, UFW + Docker firewall fix, Fail2ban, auto-updates, Docker, Coolify/CloudPanel. Lockout-proof with auto-rollback. Pure Bash.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Vps Forge

Turn a brand-new Ubuntu VPS into a secure, fast, production-ready server in minutes. An interactive terminal installer for people who don't want to learn 40 hardening guides first.

ShellCheck License: MIT Ubuntu Pure Bash PRs Welcome

sudo apt-get update -qq && sudo apt-get install -y curl ca-certificates && sudo curl -fsSL https://raw.githubusercontent.com/mh-sudo/vps-forge/main/install.sh | sudo bash
Vps Forge in action: preflight on a fresh Ubuntu VM, picking modules from the risk-tagged checklist, reviewing every change, applying 11 modules with green checks, and a final summary with the Lynis hardening index rising 63 → 71

What is Vps Forge?

Vps Forge is a free, open-source, pure-Bash terminal UI that provisions a fresh Ubuntu 22.04 or 24.04 VPS to a production-ready state. It creates a safe admin user, hardens SSH, sets up a firewall that actually works with Docker, installs Fail2ban and automatic security updates, tunes the kernel and memory, installs Docker, and can deploy a self-hosting panel like Coolify or CloudPanel.

You pick a profile, review exactly what will change, confirm, and it does the rest. Every change is backed up first, and anything that could lock you out has an automatic rollback timer.

It works on any provider that gives you Ubuntu and root: Hetzner, DigitalOcean, Vultr, Linode, OVH, Contabo, AWS Lightsail, and the rest.

Who it's for

  • You just bought a VPS to host an app, a bot, an API, an AI agent, or a side project, and you don't know what to do after the first login.
  • You've been told to "secure your server" and don't know where to start.
  • You use Docker and want published ports to be private by default.
  • You're comfortable on the command line and are tired of pasting the same 200 lines into every new box.

Why people lose servers (and what Vps Forge does about it)

Most "how to secure a VPS" guides fail beginners in the same few places.

Common failure What Vps Forge does
Changing the SSH port or disabling passwords and getting locked out Validates with sshd -t, applies changes behind a timed auto-revert, and makes you confirm from a new session before the timer is cancelled
Turning on UFW before allowing SSH Refuses. The active SSH port is allowed first, always
Disabling password login with no working key Refuses until a key for the target user is verified
Docker ports ignoring UFW, so "denied" ports are open to the internet Uses the DOCKER-USER chain so published container ports are closed by default until you allow them
Breaking something and not knowing what changed Every touched file is backed up to /var/backups/vps-forge/<timestamp>.<tag>/, and vps-forge rollback restores it
Not knowing if it worked Runs a Lynis audit before and after and shows the score difference

Quick start

Run this on a fresh server as root, or with sudo — one line, copy-paste:

sudo apt-get update -qq && sudo apt-get install -y curl ca-certificates && sudo curl -fsSL https://raw.githubusercontent.com/mh-sudo/vps-forge/main/install.sh | sudo bash

Why not just curl ... | sudo bash? Because Ubuntu Server does not come with curl preinstalled (Desktop does; minimal server/cloud images don't). The first part of that line installs it in a couple of seconds. If your box already has curl (or has wget — the installer accepts either), the short form works:

curl -fsSL https://raw.githubusercontent.com/mh-sudo/vps-forge/main/install.sh | sudo bash

The entrypoint is tiny. It downloads the files, verifies every checksum, shows live download progress, and starts the guided setup.

Prefer to read it first? Good habit.

git clone https://github.com/mh-sudo/vps-forge.git
cd vps-forge
less install.sh          # the whole entrypoint
sudo ./vps-forge

Keep a second SSH session open the entire time. Vps Forge will remind you, but it's the best safety net you have.

What you'll see

  1. Preflight. OS, RAM, disk, virtualization, current SSH user and port, detected provider, and the existing firewall state.
  2. Profile. Minimal, Recommended, Docker-Host, or Custom with a checklist. Each item has a one-line description and a risk tag.
  3. Review. A dry-run diff of exactly what will change, then an explicit confirm.
  4. Apply. Live progress per module with ✓ / ✗ / skipped.
  5. Report. A summary saved to /root/vps-forge-report.txt, the Lynis score delta, and a reboot recommendation only if one is needed.

It's built for an 80-column terminal, handles Ctrl+C safely, and uses one accent color. No ASCII-art banner.

Profiles

Profile Good for Includes
Minimal Anyone, first run Base tooling, SSH hardening, UFW, unattended security upgrades
Recommended Most single-app servers Minimal, plus sysctl hardening, swap, chrony time sync, BBR, journald limits, admin user, Fail2ban, PAM hardening, auditd, AppArmor, AIDE, rkhunter, health checks
Docker-Host Containers and self-hosting Recommended, plus Docker Engine and Compose from Docker's official apt repo, a hardened daemon.json, and the Docker-safe firewall
Custom You Pick any modules from the checklist

Features

Security hardening
  • New sudo admin user with an ed25519 SSH key, optional root login disable
  • sshd_config.d drop-in (your main config is never edited) with modern ciphers, KEX and MACs, MaxAuthTries, LoginGraceTime, AllowUsers, and a custom port option
  • UFW with default-deny incoming, rate-limited SSH, and consistent IPv6 handling
  • Fail2ban with an sshd jail (CrowdSec may be added as an alternative module)
  • Unattended security upgrades with a reboot policy
  • Kernel and sysctl hardening that doesn't break Docker or networking
  • PAM faillock, password policy, sane umask, unused services and filesystems disabled
  • AppArmor enforcing, auditd baseline rules, AIDE file integrity monitoring, rkhunter and Lynis
  • Optional TOTP 2FA for SSH with a lockout-safe flow and a backup-codes warning
Server optimization
  • Timezone, locale, chrony NTP, hostname
  • Swap file sized to your RAM, vm.swappiness, optional zram
  • File descriptor limits, TCP BBR, journald size limits, logrotate
  • Optional /tmp on tmpfs, disk TRIM
  • Base tools: curl, git, htop, ncdu, jq and friends
Production readiness
  • Docker Engine and Compose plugin (official apt repo, never the snap)
  • Caddy or Nginx reverse proxy with automatic TLS
  • node_exporter for Prometheus (loopback-only by default), a health script, and disk/RAM alerts by email or webhook
  • Scheduled restic backups to S3, SFTP, REST or a local target, with a built-in restore test
  • Tailscale, WireGuard, or Cloudflare Tunnel for private admin access
  • Deploy user, Node.js and Python runtimes
One-click panels (pick one)
  • Coolify, CloudPanel, CyberPanel
  • Requirements are pre-checked (OS, RAM, ports, conflicts with Docker, UFW, Nginx) and the install is blocked with a clear message if they aren't met
  • Only the ports the panel needs get opened, an admin password is generated and shown once, and the final access URL is printed

[!WARNING] CyberPanel has a history of serious security vulnerabilities, and real servers have been compromised through them. If you pick it, Vps Forge shows a visible warning and an extra hardening checklist. If you have a choice, consider Coolify or CloudPanel instead.

The Docker + UFW problem, fixed

This is the one that quietly bites people.

When you publish a container port (-p 8080:80), Docker adds its own iptables rules that run before UFW's. So ufw deny 8080 does nothing, and your "private" database or admin tool is open to the whole internet. Docker's own documentation describes this behavior.

Vps Forge handles it with the supported approach: custom filtering in the DOCKER-USER chain, which Docker evaluates before its own rules.

  • Published container ports are not reachable from outside by default
  • Established traffic and traffic between containers on Docker networks keep working
  • daemon.json sets the default published-port bind address to 127.0.0.1, keeps Docker's iptables management on, and survives Docker restarts and reboots
  • IPv6 is covered, and rules persist across reboots

Open a port on purpose:

vps-forge docker-allow 8080/tcp
vps-forge docker-allow 5432/tcp my-postgres-container

Don't take our word for it, prove it:

vps-forge verify-firewall

This starts a throwaway container with a published port, shows from the outside that it's blocked, opens it, shows it's reachable, and cleans up after itself.

The reasoning behind the chosen strategy, and the alternatives we compared, are in DECISIONS.md.

Commands

sudo ./vps-forge                         # interactive TUI
sudo ./vps-forge --dry-run               # show what would change, touch nothing
sudo ./vps-forge --verbose               # detailed output
sudo ./vps-forge --help

vps-forge rollback                       # restore the most recent backup set
vps-forge rollback <snapshot> --force    # scripted rollback, skips prompts
vps-forge docker-allow <port>/<proto> [comment]   # expose a published port through DOCKER-USER
vps-forge docker-deny <port>/<proto>     # close it again
vps-forge docker-fw-status               # show the DOCKER-USER rules
vps-forge verify-firewall                # prove Docker ports are private by default
vps-forge backup-test                    # prove backups restore
vps-forge panel-remove coolify|cloudpanel|cyberpanel   # uninstall a panel (asks to type the name)
vps-forge self-clean [--scope=all|panels|docker|hardening] [--yes]   # remove everything vps-forge applied
vps-forge status                         # snapshots, guards, applied modules
vps-forge guard-cancel sshd|ufw|totp     # cancel an armed auto-revert guard (from a VERIFIED new session)

Notes: self-clean is destructive and asks you to type self-clean to confirm; it only deletes users, packages and Docker data that vps-forge itself created (pre-existing sites, databases and firewall rules are left alone). panel-remove only touches the panel's own packages and configs — the web stack and site data stay.

Non-interactive mode

For automation, cloud-init, or when there's no TTY:

sudo ./vps-forge --yes --profile=recommended --config=forge.yaml
# pick specific modules instead of a profile:
sudo ./vps-forge --yes --module=sshd,ufw,fail2ban,docker,docker_fw --config=forge.yaml
# forge.yaml (flat "key: value" config; see examples/test-config.yaml)
sys.timezone: UTC
admin.username: deploy
admin.pubkey: ssh-ed25519 AAAA... you@example.com
admin.disable_root_login: false
ssh.port: 2222
fw.open_ports: 80,443
docker.bind_ip: 127.0.0.1
backup.target: none
panel: none

Configuration keys

Every key below can be set in a --config file; anything you don't set gets a safe default (the full list with defaults lives in lib/common.sh → cfg_load_defaults). Selected keys:

Key Default Meaning
sys.timezone (current) tz name, e.g. Asia/Dhaka; empty/auto keeps current
sys.hostname keep set a new hostname; keep leaves it
admin.username none admin user to create (skipped when none)
admin.pubkey (empty) SSH public key for the admin user; placeholders are refused
admin.disable_root_login false root login disabled once the admin key is verified
ssh.port keep change the SSH port (dual-listen + verify flow)
ssh.password_auth keep-until-verified no only after a key is verified
ssh.allow_tcp_forwarding false CIS default; set true if you tunnel
fw.open_ports (empty) extra UFW ports, e.g. 80,443
swap.size auto MB, or auto (RAM-based sizing)
docker.bind_ip 127.0.0.1 default bind for -p publishes (0.0.0.0 = public)
proxy.engine / proxy.domain / proxy.upstream_port none Caddy reverse proxy settings
backup.target / backup.paths / backup.schedule none restic backup settings
tailscale.auth_key (empty) join a tailnet non-interactively
wg.mode access access (server only) or full (full tunnel + NAT)
panel / panel_cyberpanel.accept_risk none / false panel choice; CyberPanel needs explicit risk acceptance
totp.enabled / totp.users / totp.confirmed false SSH TOTP 2FA for the listed users only
guard.timeout 180 auto-revert window (seconds) for sshd/ufw/TOTP guards

How it works

  • Pure Bash. set -Eeuo pipefail, an ERR trap, ShellCheck-clean, no runtime to install.
  • TUI. Uses gum (auto-installed and checksum-verified), with whiptail as a fallback.
  • Modular. lib/ holds shared helpers, modules/ holds one self-contained file per feature, and a single manifest registers them.
  • Idempotent. Every module is safe to re-run.
  • Logged. Structured logs go to /var/log/vps-forge.log.
vps-forge/
├── install.sh              # tiny verified entrypoint
├── vps-forge               # main script
├── checksums.txt           # sha256 for every shipped file
├── lib/                    # config, TUI, safety layer (snapshots + guards), preflight, runner
├── modules/                # one file per feature
│   └── manifest.conf       # the single place modules are registered
├── examples/               # non-interactive config example
├── DECISIONS.md            # design rationale + research citations
├── TESTING.md              # the full test log
└── README.md

Add your own module

  1. Create modules/my-feature.sh with the standard module functions (mod_<id>_plan/_check/_run, optional _ask).
  2. Register it in modules/manifest.conf.
  3. Open a PR. See CONTRIBUTING.md.

Requirements

  • Ubuntu 22.04 or 24.04 LTS, fresh install recommended
  • Root, or a user with sudo
  • Internet access, and curl or wget (the Quick start line installs curl for you — stock Ubuntu Server ships without it)
  • About 1 GB RAM to run (preflight flags anything under 900 MB; panels need 2 GB+, and Vps Forge checks before installing)

Threat model

Vps Forge helps defend against: automated SSH brute-forcing, exposed container ports, weak default SSH and kernel settings, unpatched packages, and misconfiguration lockouts.

It does not replace: application security, secrets management, a proper backup strategy you've tested, or monitoring someone actually looks at. A hardened server running a vulnerable app is still a vulnerable app.

Trust: you're running a script as root, so read it. The installer verifies checksums, and the source is short and modular on purpose.

FAQ

How do I secure a new Ubuntu VPS? At minimum: create a non-root sudo user, use SSH keys and disable password login, enable a default-deny firewall, install Fail2ban, and turn on automatic security updates. Vps Forge's Minimal profile does all of that, with lockout protection.

Does ufw deny protect Docker containers? No. Docker publishes ports through iptables rules that are processed before UFW's, so UFW rules don't block them. The supported fix is filtering in the DOCKER-USER chain, which Vps Forge configures for you.

Will Vps Forge lock me out of my server? It's designed not to. SSH and firewall changes are validated, applied with an automatic rollback timer, and only kept after you confirm from a new connection. It also refuses to disable password login without a verified key. Your provider's web console is the last-resort recovery path, and Vps Forge tells you how to reach it.

Can I undo what it did? Yes. Every file it touches is backed up first, and vps-forge rollback restores them. vps-forge self-clean removes everything vps-forge applied.

Is it safe to run on a server that already has stuff on it? A fresh VPS is the intended target. On an existing server, use --dry-run first and read the review screen carefully.

Does it work on Debian, AlmaLinux, or Rocky? Not yet. Ubuntu 22.04 and 24.04 only for now.

Which VPS providers work? Any that give you Ubuntu with root or sudo access.

Vps Forge or Ansible? Ansible is great if you manage many servers and want to write playbooks. Vps Forge is for one or a few servers, guided, with no setup and no YAML to learn first. They solve different problems.

Vps Forge or a hosting panel? Panels manage apps. Vps Forge secures and prepares the server underneath, and can install a panel for you afterward.

Can I use it in cloud-init or CI? Yes, via --yes --profile=... --config=....

Status

Vps Forge is beta. Live-tested end to end on Ubuntu 24.04 (2 vCPU / 2 GB KVM: module runs, full profiles, idempotency re-runs, lockout failsafes, Docker firewall proofs, all three panels, rollback and self-clean); 22.04 is supported in code but not yet live-tested. The full log is in TESTING.md. Please read the review screen before confirming, and open an issue if anything surprises you.

Development

shellcheck -S warning vps-forge install.sh lib/*.sh modules/*.sh scripts/*.sh
shfmt -d -ln bash vps-forge install.sh lib/*.sh modules/*.sh scripts/*.sh
./scripts/check.sh      # manifest <-> modules <-> install.sh <-> checksums.txt

CI runs the same gates on every push. See CONTRIBUTING.md for module conventions and the test protocol.

Security

Found a vulnerability? Please don't open a public issue. See SECURITY.md.

License

MIT


If Vps Forge saved you an afternoon (or a server), a ⭐ helps other beginners find it.

About

Vps Forge — interactive TUI that takes a fresh Ubuntu VPS to production-ready in minutes: SSH hardening, UFW + Docker firewall fix, Fail2ban, auto-updates, Docker, Coolify/CloudPanel. Lockout-proof with auto-rollback. Pure Bash.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages