Install overview
What
install.sh does, what you need before running it, and how to get from a fresh Debian box to a working portal in ~10 minutes.Supported OS
| Target | Debian version | Stack summary |
|---|---|---|
| Primary | Debian 13 (Trixie) | PostgreSQL 17 · Python 3.13 · Valkey 7.2 · BIND 9.20 · nginx 1.26 · kernel 6.12 · systemd 256+ |
| Fallback | Debian 12 (Bookworm) | PostgreSQL 15 · Python 3.11 · Redis 7.0.15 (pre-RSAL) · BIND 9.18 · nginx 1.24 · kernel 6.1 · systemd 252 |
The installer detects the OS at runtime and picks the right package set. Any other Debian major is rejected outright.
Prerequisites
- Fresh Debian 12 or 13 install (minimal is fine)
- 4 vCPU / 4 GB RAM / 60 GB disk (reference sizing for 1-4 operators)
- Root access
- A FQDN that resolves to this host (for TLS)
- Outbound HTTPS for Debian apt and (optionally) Let's Encrypt. There is no vendor phone-home — Meridian is Apache 2.0 and makes no outbound calls to MeridianNIP. Use
--airgappedif you have zero outbound at all. - Ports 80 + 443 free
What the installer does
- Pre-flight. OS + arch check, disk + RAM floors, apt sources probe, port conflicts, existing install detection.
- Interactive config. Portal name, FQDN, first admin, DB name/role, timezone, TLS method, scope (internal/external/both), SSH port, optional LUKS encryption. Every prompt has a multi-paragraph explanation before the input.
- System prep. Creates
meridianservice user,ddi-sshgroup, directory tree under/opt/meridian,/etc/meridian,/var/lib/meridian,/var/log/meridian. - Package install. Installs the OS-matched package set. Versions resolve to distro defaults; exact versions are recorded into the
version_manifesttable for drift detection. - Master key generation. Creates two 32-byte keys at
/etc/meridian/secrets/(0400owned bymeridian): the AES-GCM master for the vault and the HMAC-SHA-256 key for the tamper-evidence hash chain. - Package staging. Copies
app/,db/,scripts/,config/into/opt/meridian/; symlinks/usr/local/bin/meridian-nip. - System hardening. Applies
sysctlpolicy,logrotaterules, UFW firewall, AppArmor profiles. - Postgres setup. Creates the DB + role, loads
schema.sql, lockspg_hba.confto localhost + the meridian role only, applies the tuning overlay. - Cache setup. Starts Valkey (Debian 13) or Redis (Debian 12), localhost-bound, password-protected.
- BIND9 setup. Recursive resolver on
127.0.0.1only, used by the dig sandbox. - App install. Creates the Python venv, pip-installs from pinned
requirements.txt, writesmeridian.conf, renders + enables the three systemd units (meridian-app,meridian-celery,meridian-beat). - Nginx + TLS. Based on the chosen method: Let's Encrypt (certbot + HTTP-01), Cloudflare origin cert, self-signed, or HTTP-only dev mode.
- SSH hardening. Custom port,
AllowGroups ddi-ssh, modern KEX/ciphers/MACs only, legal MOTD banner — all via asshd_config.d/10-meridian.confdrop-in. - fail2ban. sshd, nginx-bad-request, nginx-req-limit, and a Meridian-login jail that reads the audit log.
- First admin seed. Creates the super-admin account with an auto-generated temp password.
- Start services and smoke-test. Hits
/healthz. - Summary. Prints every credential on-screen and to
/root/meridian-install.logwith an offer toshred -uonce you've saved them.
Dependency sources
Meridian pulls dependencies from two places at install time:
| Layer | Source | Why |
|---|---|---|
| OS packages (nginx, bind9, postgresql, valkey, etc.) | apt from Debian | Security patches land within hours of release; signed Release files verified by apt. |
| Python dependencies (~30 packages) | Pinned requirements.txt against PyPI | Hashes pinned per --require-hashes for reproducibility. Pip resolves them at install time. |
NO PHONE-HOME
The only outbound calls
install.sh makes are to apt and (optionally) Let's Encrypt. There is no license server, no telemetry, no vendor check-in — Apache 2.0, source on GitHub, you read the code. The --airgapped flag skips even apt/Let's Encrypt if you're staging onto an isolated network with a local mirror.Getting the source
Two ways to get a working tree of the same release:
- Tag download from GitHub — visit releases/tag/v1.0.0, download "Source code (tar.gz)" or use
git clone --branch v1.0.0 https://github.com/MeridianNIP/meridian.git - Latest
main—git clone https://github.com/MeridianNIP/meridian.gitfor the rolling tip; tagged releases are the stable cut.
For Hyper-V / VMware / VirtualBox installs there's also a prebuilt Debian-13.4 ISO attached to the release page (940 MB, UEFI-bootable, preseed-injected). Install instructions on the site walk you through which path to pick.
Running the installer
# From the source directory:
sudo ./install.sh
# Upgrade an existing install:
sudo ./install.sh --upgrade
# Pre-flight only (no changes):
sudo ./install.sh --dry-run
# Unattended (every prompt comes from an answers file):
sudo ./install.sh --unattended --config /opt/meridian/answers.local.env
# No internet access available:
sudo ./install.sh --airgapped # no outbound calls; apt pointed at a local mirror
After install
- Browse to
https://<your-domain>/ - Sign in with the admin username and temp password from the summary
- Accept the AUP (prompted automatically)
- Enroll MFA
- Admin → Branding — upload logo, set AUP text, set the logo click-through URL
- Admin → Scope Manager — enable only the features your team uses
- Admin → Integrations — connect AD, Infoblox, Slack, etc.
- Back up the master keys at
/etc/meridian/secrets/to secure offline storage
CRITICAL
The master keys at
/etc/meridian/secrets/ cannot be regenerated. If you lose them, the database (and every backup that doesn't include them) is permanently unreadable. Back them up immediately after first install.Troubleshooting
- Installer aborted mid-way → see
/root/meridian-install.logfor the full transcript - Services won't start →
journalctl -u meridian-app -n 100 - App
/healthzfails →sudo -u meridian /opt/meridian/venv/bin/python -m app.cli doctor - TLS issues →
nginx -tandcertbot certificates - General environment health →
sudo /opt/meridian/scripts/doctor.sh
MERIDIAN 1.0.0 · DOCUMENTATION