panelOwl docs 1.15.0

Installation

Requirements

SSH lockout protection. If your sshd_config already contains AllowUsers, AllowGroups, DenyUsers or DenyGroups, the installer stops. panelOwl installs its own AllowGroups drop-in and sshd ANDs such directives; remove yours first (the installer adds root, every sudo/adm member and the invoking user to the root-access group so nobody gets locked out).

Before you start: DNS

Create these records at your DNS provider before running the installer, so the hostname certificate can be issued immediately:

Record Name Value
A panel.hoster.example the server's public IPv4
AAAA panel.hoster.example the server's public IPv6 (only if the server actually has one)
PTR (reverse DNS) server IPv4 panel.hoster.example — set at your server provider; needed for outbound mail reputation

Set the system hostname too: hostnamectl set-hostname panel.hoster.example.

Getting the release onto the server

Releases are published at https://panelowl.com/releases/ as a signed tarball, minipanel-<version>.tar.gz, next to latest.json (the manifest the update feed reads). On the new server, logged in as a user with sudo:

cd ~
curl -fsSLO https://panelowl.com/releases/latest.json
v=$(python3 -c 'import json; print(json.load(open("latest.json"))["version"])')
curl -fsSLO "https://panelowl.com/releases/minipanel-$v.tar.gz"
curl -fsSLO "https://panelowl.com/releases/minipanel-$v.tar.gz.sha256"
sha256sum -c "minipanel-$v.tar.gz.sha256"

(Or copy the file from wherever you have it with scp minipanel-<version>.tar.gz user@server:.)

Running the installer

On the server, unpack and run the installer as root:

cd ~
tar xzf minipanel-$v.tar.gz
cd minipanel-$v
sudo ./install/install.sh --hostname panel.hoster.example --email admin@hoster.example

The installer shows every setting it is about to use and asks for confirmation (press Enter to accept the value in brackets). Options:

Flag Meaning
--hostname FQDN server hostname (default: hostname -f)
--email ADDRESS admin email registered with Let's Encrypt
--php 8.3[,8.4] PHP versions to install (default 8.3); more can be added later with panelctl php install
--public-ipv4 IP the address clients' DNS records should point at. Detected automatically, but behind NAT the detection sees the firewall's outbound address, which may differ from the one forwarded to the server — pass the forwarded address
--public-ipv6 IP likewise for IPv6, or none
--update-url URL release feed the server updates from (default https://panelowl.com/releases/; a private mirror is fine, the manifest is signed either way)
--skip-dns-check continue even if the hostname does not resolve to this server (the certificate is then requested later by the hourly timer)
--yes no prompts; requires --hostname and --email on a first install
--force continue despite an existing web/mail/database stack or busy ports
--skip-resource-check warn instead of abort below 2 GB RAM / 20 GB disk (test environments only)

It takes about five minutes and is safe to re-run. What it does, in order:

  1. Preflight checks (OS, root, resources, existing services, sshd directives).
  2. Adds the PHP PPA with a pinned signing key, installs Apache, PHP-FPM, MariaDB, Postfix, Dovecot, Rspamd, Redis, fail2ban, certbot, ufw and unattended-upgrades (security updates only).
  3. Creates the minipanel user, the groups minipanel-sftp, minipanel-ssh, minipanel-nopass and root-access, and the directories under /var/lib/minipanel, /var/log/minipanel, /etc/minipanel.
  4. Installs the binaries to /usr/local/lib/minipanel/ (with panelctl linked into /usr/local/sbin/), the systemd units and the version marker.
  5. Writes /etc/minipanel/config.toml (hostname, admin email, detected public IPs, PHP versions, default limits).
  6. Generates a self-signed bootstrap certificate, then writes the base configuration of every service: default Apache vhosts (unknown hosts get a 404 page, the hostname redirects to the panel), PHP-FPM placeholder pools, MariaDB with secure defaults, Postfix/Dovecot/Rspamd for virtual mailboxes with DKIM, the sshd drop-in, /etc/cron.allow, fail2ban jails, sysctl hardening, logrotate, ufw rules.
  7. Starts minipaneld, runs the schema migrations and panelctl rebuild, then requests the hostname certificate from Let's Encrypt.
  8. Prints a summary with the panel URL and the DNS/PTR records to verify.

Behind a NAT firewall

panelOwl works fine on a private address behind a firewall that forwards ports (pfSense/OPNsense, a home router, a cloud NAT). Two things to get right:

From inside the same LAN, the public address only works if the firewall does NAT reflection (hairpin); otherwise use the server's LAN address, and add hosts-file entries on your PC to test client sites before their DNS exists.

After installation

Check the server's health and the certificate:

panelctl doctor
panelctl ssl status

Until the hostname certificate is issued, the panel, mail services and default vhost use the self-signed bootstrap certificate; browsers and mail clients will warn. The panel is also reachable by IP address (https://<ip>:8443/) for a first look, with the same warning. Client sites are selected by hostname, so a site opened by IP shows the server's "Site not found" page. The hourly minipanel-ssl.timer retries issuance once DNS is correct; panelctl ssl retry panel.hoster.example forces an attempt.

Create the first client account:

panelctl account create acme --domain example.com --email owner@example.com

This prints the panel URL, the account's generated password (shown once) and the DNS records the client must create. See panelctl reference for all options, and hand the client the Getting started page.

What the installer configures, by service

Service Configuration written Notes
Apache /etc/apache2/minipanel/ (global + one file per domain), mod_proxy_fcgi to PHP-FPM sockets AllowOverride All, .htaccess works; php_value in .htaccess does not (PHP-FPM)
PHP-FPM /etc/php/<ver>/fpm/pool.d/minipanel-<account>.conf one pool per account and version, pm = ondemand, runs as the account user
MariaDB bind-address = 127.0.0.1, root via Unix socket, no test DB / anonymous users clients connect to localhost only
Postfix /etc/postfix/main.cf, master.cf, maps in /etc/postfix/minipanel/ submission 587 (STARTTLS) and 465 (TLS), SASL via Dovecot, senders restricted to their own address, Rspamd milter
Dovecot /etc/dovecot/conf.d/99-minipanel.conf, passwd files /etc/dovecot/minipanel-* IMAPS 993 / POP3S 995 only, Maildir under /home/<account>/mail/, quotas, Sieve files spam into Junk
Rspamd /etc/rspamd/local.d/ DKIM signing with per-domain keys in /var/lib/rspamd/dkim/, 200 messages/hour per mailbox, spam tagged (never rejected by score)
sshd /etc/ssh/sshd_config.d/50-minipanel.conf AllowGroups root-access minipanel-sftp minipanel-ssh; SFTP-only accounts get internal-sftp
cron /etc/cron.allow = root; crontabs rendered by the helper clients edit cron only through the panel
fail2ban /etc/fail2ban/jail.local sshd, Postfix SASL, Dovecot and panel-login jails
ufw ports listed under Requirements everything else denied
certbot /etc/letsencrypt/renewal-hooks/deploy/minipanel renewals reload Apache (and Postfix/Dovecot for the hostname certificate)
backups minipanel-backup.timer, /var/backups/minipanel/ nightly full archive at 03:00; see Operations
webmail, phpMyAdmin Roundcube + phpMyAdmin from Ubuntu's archive, pool minipanel-apps, https://<hostname>/webmail/ and /phpmyadmin/ see Operations
admin UI minipanel-admin.service (user minipanel-admin, 127.0.0.1:8082), Apache on 2087 create logins with panelctl admin create; restrict port 2087 to admin addresses