Fresh install on Oracle Linux 9 / 10
Step-by-step for installing customsso-manager on a brand-new Oracle Linux 9 or 10 minimal VPS + pairing it with one PBX.
RHEL / Rocky / AlmaLinux 9 / 10 also ride this branch (share the dnf + httpd + firewalld + SELinux paths) but are less formally tested; anything you learn on OL applies verbatim.
Requirements before you start
- [ ] A VPS or VM running Oracle Linux 9 or 10 minimal. Fresh install; no other services yet.
- [ ] 10+ GB free on
/(fresh-install footprint is around 3 GB; leaves comfortable room for logs, /tmp jobs, and 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) — the install one-liner downloads the release tarball from there. - [ ] 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.
Step 1 — Prep the VPS
# On the fresh VPS as root
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 components (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 if you need to change it after install.
The installer runs dnf -y update 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 dnf -y update && reboot now and pick up at Step 2 after the box comes back.
Step 2 — Run the install one-liner
curl -sSfL https://git.voip-stuff.net/customsso-manager/install.sh -o /tmp/setup.sh && sudo bash /tmp/setup.sh
The bootstrap script downloads the latest release tarball, verifies its SHA256, extracts, and execs install.sh. The 16 steps then run:
- Detect Oracle Linux + populate RHEL-family variables
dnf -y update- Install EPEL
- Install runtime deps:
httpd,mod_ssl,php-fpm+ extensions,mariadb-server,python3,msmtp,fail2ban,firewalld,certbot, ... - Create Python sidecar venv (
paramiko,cryptography,mysql-connector-python, ...) 5b. Create output spool dir at/var/spool/customsso/with SELinux labelhttpd_sys_rw_content_t5c. Sync system + PHP + MariaDB timezones - 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 - Neutralize stock
ssl.conf(OL9's default<VirtualHost _default_:443>hijacks the HTTPS handshake and serveslocalhost.localdomain's snake-oil cert on every LAN-IP hit — install.sh comments out the offending vhost block and backs it up as.pre-customsso) + write our vhost + generate self-signed cert with SAN entries for the primary IP + hostname + localhost - Configure
firewalld:--add-service=https/http/ssh - Apply SELinux
fcontextlabels +setsebool -P httpd_can_network_connect 1 - Configure
fail2banjail for the manager's audit log systemctl enable+restartmariadb, httpd, php-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 (rhel: /etc/httpd/conf.d/customsso-manager.conf)
neutralized stock ssl.conf VirtualHost block (backup at ssl.conf.pre-customsso)
[11/16] firewalld
[12/16] SELinux
[13/16] fail2ban
[14/16] sidecar service
[15/16] first admin
================================================================
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 — 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 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 5 — Pair with a test PBX
Sidebar → + Add PBX. Enter host + root password + label. Click Pair. Watch the transcript at /pair/progress/{job}.
Behind the scenes 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 6 — 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 (both sides must be HTTPS, and the agent must have "Allow framing" enabled).
- [ ] fwconsole tab → dispatch
fwconsole reload→ job goespending → running → complete. - [ ] Terminal tab → PTY loads.
- [ ] Sidebar
S(System) +V(VoIP) letter badges populate green.
Step 7 — Test the --update path
To refresh to a newer release without touching DB or master key:
curl -sSfL https://git.voip-stuff.net/customsso-manager/install.sh -o /tmp/setup.sh
sudo bash /tmp/setup.sh -- --update
Expected: app files refresh, DB + master key + admins + paired PBXes preserved, vhost backed up before rewrite (.pre-<timestamp>), migrations run any new NNN_*.sql, sidecar restarts.
OL9-specific gotchas
- Stock
ssl.confhijack — the neutralization step at line 10 is essential. Without it, browsers see aCN=localhostsnake-oil cert and Apache 404s every route. The.pre-customssobackup lets you inspect what was there originally if you ever need multi-tenant HTTPS on the same box outside customsso-manager. - SELinux
httpd_sys_rw_content_t— the manager needs both READ and WRITE onmsmtprc,master.key,/var/spool/customsso/. If you copy files into place manually (not via install.sh), runrestorecon -Ron the affected paths. firewall-cmd --add-service=https/ssh— install.sh opens these two by default. If you want the manager LAN-only,firewall-cmd --add-rich-rule='rule family=... source address=<your-subnet> ...'per your policy.
Rollback
/etc/customsso-manager/, /var/www/customsso-manager/, /opt/customsso-manager/, the DB, and the fail2ban / vhost / spool paths listed at install time are the only things touched. Wiping those + dnf remove on the packages returns the box to baseline. On a VPS the cheapest recovery is destroy + re-provision.