Fresh install on Debian 12 / 13
Step-by-step for installing customsso-manager on a brand-new Debian 12 (bookworm) or 13 (trixie) minimal VPS + pairing it with one PBX. Added in v0.6.0.
Ubuntu 22.04 (jammy) and 24.04 (noble) also ride the Debian branch (share the apt + apache2 + www-data + no-SELinux paths). Less formally tested than Debian; open an issue via signing@voip-stuff.net if something breaks.
Requirements before you start
- [ ] A VPS or VM running Debian 12 or 13 minimal (or Ubuntu 22.04 / 24.04). Fresh install; no other services yet.
- [ ] 10+ GB free on
/(fresh-install footprint is around 3.5 GB on Debian; leaves comfortable room for logs, /tmp jobs, MariaDB growth). - [ ] 1 vCPU / 1 GB RAM minimum; 2 vCPU / 2 GB RAM recommended for fleets over ~20 PBXes.
- [ ] Root SSH access to the box.
- [ ] Outbound network reach to
git.voip-stuff.net(443/tcp) anddeb.debian.org/security.debian.org(443/tcp) — the install one-liner + apt need these. - [ ] At least one FreePBX 16 or 17 box with root SSH access from the manager, for smoke-testing the pair flow at the end.
- [ ] An SMTP relay you can use for 2FA + password-recovery + fleet-alert emails. Fill it in AFTER first-run through
Settings → Mail; the box will install without it. - [ ]
curl— minimal Debian images ship without it. If missing:apt-get -y install curl. - [ ] Debian minimal ships without
sudo. You have two options: (a) run the install as root directly (drop thesudoprefix from the one-liner below), or (b) install sudo yourself first (apt-get -y install sudo, then add your admin user to thesudogroup). Either way, install.sh addssudoto the package list so it's present after the install completes — you only need to work around this for the install command itself.
Step 1 — Prep the VPS
# On the fresh VPS as root
apt-get -y install curl # if not already present
hostnamectl set-hostname manager-test.lan # or whatever
timedatectl set-timezone America/Chicago # set BEFORE install
About the timezone: set it BEFORE running the installer. The installer reads your OS timezone and pins PHP + MariaDB to match — all three (OS, PHP, MariaDB) must agree, or "X ago" calculations drift and short-TTL rows (2FA codes, password-reset links) mis-expire. If the OS is still on UTC when you install and you change it later, PHP will remain on UTC and you'll see a 5+ hour skew in the audit log. See TIMEZONE.md for the retune ritual.
The installer runs apt-get update && apt-get upgrade itself (step 2 of 16); no need to do it here. If you'd rather reboot on your schedule than let one land mid-install, run apt-get -y update && apt-get -y dist-upgrade && reboot now and pick up at Step 2 after the box comes back.
Step 2 — Run the install one-liner
# If you're logged in as root (typical on Debian minimal): drop the sudo prefix
curl -sSfL https://git.voip-stuff.net/customsso-manager/install.sh -o /tmp/setup.sh && bash /tmp/setup.sh
# If you already have sudo set up:
curl -sSfL https://git.voip-stuff.net/customsso-manager/install.sh -o /tmp/setup.sh && sudo bash /tmp/setup.sh
Fresh Debian minimal note: the base image doesn't include sudo at all. bash /tmp/setup.sh (no prefix) is the correct invocation when you're logged in as root, which is the default admin user on Debian minimal. The installer will add sudo to the package list during step 4, so all follow-up commands (like sudo cat /etc/customsso-manager/first-run.token if you need to re-read the boot-token URL) will work once the install finishes.
The bootstrap script downloads the latest release tarball, verifies its SHA256, extracts, and execs install.sh. Debian branch runs these 16 steps:
- Detect Debian + populate
www-data/apache2/aptvariables apt-get -y update && apt-get -y upgrade- (skipped on Debian — no EPEL equivalent needed)
- Install runtime deps:
apache2,libapache2-mod-fcgid,php+php-fpm+ extensions,mariadb-server,python3+python3-venv,msmtp msmtp-mta,fail2ban,certbot, ... - Create Python sidecar venv (
paramiko,cryptography,mysql-connector-python, ...) 5b. Create output spool dir at/var/spool/customsso/5c. Sync system + PHP + MariaDB timezones (PHP conf goes into/etc/php/8.x/mods-available/99-customsso-timezone.iniand gets linked into every SAPI viaphpenmod; MariaDB conf into/etc/mysql/mariadb.conf.d/customsso.cnf) - Initialize MariaDB, create app DB + user
- Generate 32-byte master key at
/etc/customsso-manager/master.key - Copy web files →
/var/www/customsso-manager/; sidecar →/opt/customsso-manager/ - Apply migrations from
src/schema/*.sql - Write vhost to
/etc/apache2/sites-available/customsso-manager.conf; generate self-signed cert with SAN entries for the primary IP + hostname + localhost;a2enmod ssl proxy proxy_wstunnel proxy_http rewrite headers && a2ensite customsso-manager - Firewall (no auto-configuration on Debian) — install.sh prints a reminder to configure
ufwornftablesper your policy. Required ports:- 443/tcp INBOUND (manager UI)
- 22/tcp OUTBOUND (SSH to paired PBXes)
- 587/tcp OUTBOUND (SMTP to your relay, if not 25/465)
- (skipped on Debian — no SELinux; AppArmor's stock
apache2profile doesn't block anything the manager needs) - Configure
fail2banjail for the manager's audit log systemctl enable+restartmariadb, apache2, php8.x-fpm, customsso-sidecar- Generate first-run boot token; print the URL
- Print final summary
Optional flags
sudo bash /tmp/setup.sh -- --listen-host sso.example.com
sudo bash /tmp/setup.sh -- --update # refresh app files, preserve DB + master key
sudo bash /tmp/setup.sh -- --admin-user alice --admin-pass 's3cret!' --listen-host sso.example.com
sudo bash /tmp/setup.sh -- --require-luks # refuse if / is not LUKS-encrypted
Expected output near the end:
[10/16] Apache vhost (debian: /etc/apache2/sites-available/customsso-manager.conf)
[11/16] firewall (no auto-configuration on debian)
[i] No firewall was configured. If you're using ufw / nftables, allow:
443/tcp INBOUND (manager UI)
22/tcp OUTBOUND (SSH to paired PBXes)
587/tcp OUTBOUND (SMTP to your relay, if not 25/465)
[12/16] (skipped on debian — no SELinux)
[13/16] fail2ban
[14/16] sidecar service
================================================================
First-admin boot token generated. To finish setup, open:
https://<your-host>/setup?token=<64-hex>
================================================================
=============================================
customsso-manager v0.6.x installed
=============================================
Step 3 — Claim the boot token from a browser
- [ ] Copy the URL from the terminal (or SSH back in and
cat /etc/customsso-manager/first-run.tokenif it scrolled off). - [ ] Paste it into your browser. Accept the self-signed cert warning.
- [ ] "Create the first admin" form → enter username / email / password (min 7 chars).
- [ ] Submit — you're auto-logged in and land on the empty Fleet dashboard.
Sanity check: sudo cat /etc/customsso-manager/first-run.token should now be empty (truncated on successful setup). Retrying the URL shows "setup already complete."
Step 4 — Configure your firewall (Debian-specific)
Because install.sh doesn't auto-configure a firewall on Debian, decide how you want to handle it before going into production.
Option A: ufw (simplest)
apt-get -y install ufw
ufw allow 443/tcp comment 'customsso-manager UI'
ufw allow 22/tcp comment 'SSH admin access'
ufw --force enable
Outbound is open by default with ufw's stock policy — the sidecar's SSH to paired PBXes + msmtp's SMTP relay reach out without extra rules.
Option B: nftables (native Debian default)
Edit /etc/nftables.conf with the input rules for 443 + 22, then systemctl enable nftables && systemctl restart nftables. See the Debian nftables wiki for a template.
Option C: No host firewall
Fine if the manager is on a private LAN or behind a cloud VPC security group. Skip.
Step 5 — First smoke tests (before pairing)
- [ ] Sign out. Sign back in. First login from a new IP triggers the 2FA email code — you'll land on
/login/2fa. - [ ] Email working? — enter the 6-digit code. That (user, source-IP) pair goes to
trusted_devices; next sign-in from the same IP skips 2FA. - [ ] Email not working? — Fine for now.
Settings → Mail→ fill in your SMTP relay,Save & Send test, sign out, sign back in. - [ ] Forgot password test: on the login page, click "Forgot my password", submit the admin email. Check inbox for the one-shot reset link.
Step 6 — Pair with a test PBX
Sidebar → + Add PBX. Enter host + root password + label. Click Pair. Watch the transcript at /pair/progress/{job}.
The sidecar SSHes in as root, installs the customsso agent module, drops the SSO landing endpoint + Apache alias, writes a manifest of everything it created, installs its own SSH pubkey with from=<manager-ip>, then wipes the root SSH password. The root password never touches manager disk.
The dashboard flips the PBX from unknown → ok within ~60 s.
Step 7 — End-to-end smoke test on the paired PBX
- [ ] Click the PBX → Status tab shows base URL / SSH host / disk %.
- [ ] Native UI tab loads the PBX admin in an iframe.
- [ ] fwconsole tab → dispatch
fwconsole reload→ job goespending → running → complete. - [ ] Terminal tab → PTY loads.
- [ ] Sidebar
S(System) +V(VoIP) letter badges populate green.
Debian-specific gotchas
php-fpmis versioned —php8.2-fpmon Debian 12,php8.3-fpmon Debian 13. install.sh auto-detects and pins the right service; if you upgrade PHP later (apt install php8.3), the customsso timezone conf gets picked up automatically because it lives in/etc/php/8.x/mods-available/andphpenmodlinked it into all SAPIs.- Vhost must be enabled — install.sh runs
a2ensite customsso-manager && a2enmod ssl proxy proxy_wstunnel proxy_http rewrite headersat step 10. If you replace the vhost by hand, make sure these modules stay enabled ora2query -mwill show them missing. - No default vhost hijack — unlike OL9's stock
ssl.conf, Debian'ssites-enabled/starts empty. Our vhost wins the handshake without any neutralization step needed. - AppArmor is on but not blocking — the stock
usr.sbin.apache2AppArmor profile has broad/var/www/read +/var/log/apache2/write permissions that cover everything the manager does. If you tighten AppArmor for your fleet, make sure the profile allows read + write on/var/spool/customsso/,/etc/customsso-manager/msmtprc, and/var/log/msmtp.log. aptmay not acceptapt-keywarnings — Debian's apt sometimes complains about deprecated keys duringapt-get update. Doesn't stop the install; ignore the warnings during step 2.
Step 8 — Test the --update path
curl -sSfL https://git.voip-stuff.net/customsso-manager/install.sh -o /tmp/setup.sh
sudo bash /tmp/setup.sh -- --update
Same behavior as OL9: app files refresh, DB + master key + admins + paired PBXes preserved, vhost backed up as .pre-<timestamp>, migrations run any new NNN_*.sql, sidecar restarts.
Rollback
Only these paths are touched by install: /etc/customsso-manager/, /var/www/customsso-manager/, /opt/customsso-manager/, /var/spool/customsso/, the DB, /etc/apache2/sites-*/customsso-manager.conf, /etc/apache2/customsso-manager-tls/, /etc/fail2ban/jail.d/customsso-manager.conf, /etc/php/*/mods-available/99-customsso-timezone.ini, /etc/mysql/mariadb.conf.d/customsso.cnf. Wipe those + apt-get remove on the packages returns the box to baseline. On a VPS the cheapest recovery is destroy + re-provision.