panelOwl docs 1.15.0

Command quick reference

Everything an admin runs from a root shell on the server, on one page. All panelctl commands need root (sudo), take --json before the command for machine-readable output, and exit 1 with a one-line message on error. Generated passwords are printed once.

Install and upgrade

tar xzf minipanel-<version>.tar.gz && cd minipanel-<version>
sudo ./install/install.sh --hostname panel.example.com --email admin@example.com   # first install
sudo ./install/install.sh --yes                                                    # upgrade / re-apply, keeps settings
sudo ./install/install.sh --hostname new.example.com --public-ipv4 203.0.113.10    # change hostname / public address
Installer flag Meaning
--hostname FQDN server hostname (panel, mail and SFTP name)
--email ADDRESS Let's Encrypt contact
--php 8.3[,8.4] PHP versions to install
--public-ipv4 IP / --public-ipv6 IP|none address clients' DNS should point at (behind NAT: the forwarded one)
--skip-dns-check continue if the hostname does not resolve here yet
--yes no prompts
--force continue despite existing services / busy ports / sshd Allow-Deny rules
--skip-resource-check allow < 2 GB RAM / 20 GB disk (test boxes)
panelctl version          # installed version
panelctl ping             # daemon alive, uptime, schema version
panelctl doctor           # services, configs, disk, DB, DNS, certs, apply state, backups, updates
panelctl update check     # ask the signed release feed ([update] url in config.toml)
panelctl update apply     # download, verify, install the newer release (add --force to reinstall)
panelctl update status    # progress and installer log of the last update

Accounts

panelctl account create NAME --domain DOMAIN --email ADDRESS [--php 8.4] [--ssh off|sftp|shell] [--password-stdin]
panelctl account list
panelctl account show NAME
panelctl account suspend NAME
panelctl account unsuspend NAME
panelctl account passwd NAME [--password-stdin]        # new panel/SFTP/SSH password
panelctl account modify NAME --email E --php 8.3       # contact email, default PHP for new domains
panelctl account delete NAME --confirm NAME            # archives first (kept 30 days), then removes everything
panelctl account delete NAME --confirm NAME --no-backup   # no archive: irreversible
panelctl account restore minipanel-deleted-NAME-<time>.tar.gz --confirm   # bring a terminated account back
panelctl ip list                                       # IP pool, usage, spare addresses on the server
panelctl ip add 203.0.113.10 --label shop              # an address already in netplan
panelctl ip add 10.0.0.12 --public 198.51.100.12       # behind NAT: local + public (DNS) address
panelctl ip assign 203.0.113.10 a.com b.com c.com      # move domains to an address
panelctl ip assign shared a.com                        # back to the shared address
panelctl ip remove 203.0.113.10 --force                # its domains go back to the shared address
panelctl account limits NAME --cpu 100 --memory 1G --procs 100   # resource limits (one core, 1 GB, 100 processes)
panelctl account limits NAME --cooldown on             # pause automatically when it stays at a limit
panelctl account limits NAME --restore                 # resume a paused account now
panelctl limits status                                 # enforced controllers, paused accounts
panelctl limits usage                                  # live CPU/memory/process/IO per account
printf '%s' 'the password' | panelctl account create NAME --domain D --email E --password-stdin

Account names: 3–16 characters, a-z0-9, starting with a letter; they become Unix users (uid 2000+). Clients log in at https://<hostname>:8443/ with the account name or primary domain.

Disk quotas

panelctl quota status
panelctl quota enable                   # once; edits /etc/fstab (ext4: live, XFS: after a reboot)
panelctl account quota NAME 10G         # 500M, 1T, unlimited
sudo repquota -u /                      # raw usage/limits per user

Domains, certificates, PHP

panelctl domain list [--account NAME]
panelctl ssl status                    # every certificate: state, names, expiry, next attempt
panelctl ssl retry DOMAIN              # request now, ignoring backoff (after DNS is fixed)
panelctl ssl deployed CERT-NAME        # what certbot's renewal hook calls; reloads services
panelctl ssl tick                      # what the hourly timer runs
panelctl php list
panelctl php install 8.4               # from the PPA; clients can then pick it
panelctl php set-default 8.4           # for new accounts

DNS

panelctl dns status
panelctl dns setup powerdns --ns ns1.example.net --ns ns2.example.net   # install PowerDNS here
echo "$TOKEN" | panelctl dns setup cloudflare --token-stdin [--account-id ID]
echo "$TOKEN" | panelctl dns setup cpanel --url https://dns1.example.net:2087 --token-stdin
panelctl dns zones                     # every zone: status, last error
panelctl dns zone example.com          # its records
panelctl dns sync [example.com]        # publish now (the timer does it every 5 min)
dig +short @127.0.0.1 example.com A    # PowerDNS answering locally

Suspended and pause pages

panelctl page show suspended           # what suspended accounts' visitors see
panelctl page set suspended --file my.html
panelctl page set limited --file my.html   # default for sites paused by the limiter
panelctl page show example.com         # that domain's own pause page (client-editable)
panelctl page reset example.com

Settings and notifications

panelctl config show
panelctl config set public_ipv4 203.0.113.10        # behind NAT: the forwarded address
panelctl config set public_ipv6 none
panelctl config set admin_email admin@example.com
panelctl config set notify_email ops@example.com    # empty = admin_email
panelctl config set notify off                      # or on
panelctl config set fail2ban_ignore 10.0.1.0/24 203.0.113.7   # never banned; '' clears
panelctl config set update_url https://updates.example.com/minipanel/
panelctl notify --test                              # mail the current health state now

Each set validates, saves config.toml and restarts minipaneld. The hostname is changed with install.sh --hostname NEW --yes (it is wired into Postfix, Dovecot and certificates).

Configuration and repair

panelctl rebuild                       # re-render every managed file from the state DB, reload services
panelctl rebuild --account NAME        # one account (after fixing an apply error)
panelctl usage refresh                 # re-measure disk usage (daily timer does this)
sudo nano /etc/minipanel/config.toml && sudo systemctl restart minipaneld   # settings: hostname, IPs, limits, backup retention

Managed files (never edit by hand — rebuild overwrites them): /etc/apache2/minipanel/, /etc/php/*/fpm/pool.d/minipanel-*.conf, /etc/postfix/minipanel/, /etc/dovecot/minipanel-*, /etc/ssh/sshd_config.d/50-minipanel.conf, /var/spool/cron/crontabs/<account>.

Backups

panelctl backup run                    # full archive to /var/backups/minipanel (nightly 03:00)
panelctl backup run --account NAME     # one account
panelctl backup list
panelctl backup restore FILE --account NAME --confirm   # one account's home + databases, into the existing account
panelctl backup restore FILE --confirm                  # whole server (fresh install + archive); restarts minipaneld, rebuilds
rsync -a /var/backups/minipanel/ backup-host:minipanel/ # offsite copy: your job

Admin web UI (port 2087)

panelctl admin create NAME [--password-stdin]   # login for https://<hostname>:2087/; first login sets up 2FA
panelctl admin list
panelctl admin passwd NAME [--password-stdin]   # new password, clears a lockout
panelctl admin totp-reset NAME                  # lost authenticator: next login sets it up again
panelctl admin delete NAME
sudo ufw delete allow 2087/tcp && sudo ufw allow from 203.0.113.0/24 to any port 2087 proto tcp   # restrict to admin addresses

Audit and logs

panelctl audit                                  # newest 100 entries
panelctl audit --account NAME --since 7d --limit 500
panelctl --json audit | jq '.[] | select(.result != "ok")'
sudo journalctl -u minipaneld -u minipanel-web -u minipanel-admin --since today
sudo journalctl -u minipanel-web | grep 'login failed'          # what fail2ban sees
sudo tail -f /var/log/apache2/minipanel/<account>/<domain>-error.log
sudo tail -f /var/log/mail.log /var/log/rspamd/rspamd.log

Services

systemctl status minipaneld minipanel-web minipanel-admin
systemctl list-timers 'minipanel-*'            # ssl (hourly), usage (daily), backup (03:00)
sudo systemctl restart minipaneld              # after editing config.toml
sudo systemctl reload apache2 php8.3-fpm postfix dovecot
sudo apachectl configtest; sudo postfix check; sudo doveconf -n >/dev/null; sudo sshd -t; sudo php-fpm8.3 -t
Unit Runs as Listens
minipaneld root /run/minipanel/helper.sock
minipanel-web minipanel 127.0.0.1:8081 → Apache 8443
minipanel-admin minipanel-admin 127.0.0.1:8082 → Apache 2087
apache2, php8.x-fpm, mariadb, postfix, dovecot, rspamd, redis-server, fail2ban, cron, ssh system 80/443, sockets, 25/465/587/993/995, 22

Firewall and fail2ban

sudo ufw status numbered
sudo fail2ban-client status                    # jails: sshd, postfix-sasl, dovecot, minipanel-panel
sudo fail2ban-client status minipanel-panel
sudo fail2ban-client banned
sudo fail2ban-client unban 203.0.113.7
sudo fail2ban-client set sshd addignoreip 10.0.1.0/24   # until restart; make permanent in jail.local

Open ports: 22, 25, 80, 443, 465, 587, 993, 995, 8443 (client panel), 2087 (admin UI). Behind NAT, forward the same list.

Mail diagnostics

sudo doveadm auth test user@example.com 'password'      # mailbox credentials
sudo doveadm quota get -u user@example.com
sudo postmap -q example.com hash:/etc/postfix/minipanel/virtual_domains
sudo postmap -q user@example.com hash:/etc/postfix/minipanel/virtual_mailboxes
sudo postqueue -p; sudo postqueue -f                    # queue, flush
sudo rspamadm configtest
openssl s_client -connect panel.example.com:993 -quiet </dev/null   # IMAPS banner + certificate chain
ls -l /var/lib/rspamd/dkim/                             # per-domain DKIM keys

Webmail and phpMyAdmin

https://<hostname>/webmail/  and  https://<hostname>/phpmyadmin/
sudo tail -f /var/lib/minipanel/apps/roundcube/logs/errors.log      # webmail failures (fail2ban: roundcube-auth)
sudo journalctl -t phpMyAdmin                                        # phpMyAdmin denials (fail2ban: phpmyadmin-syslog)
sudo tail -f /var/lib/minipanel/apps/logs/php-error.log
# switch off: [apps] webmail = false / phpmyadmin = false in config.toml, then:
sudo ./install/install.sh --yes

Databases

sudo mariadb                                            # root over the socket
sudo mariadb -e "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA"
sudo mariadb -e "SELECT user, host FROM mysql.user WHERE user LIKE 'acme_%'"
sudo mariadb-dump --single-transaction acme_shop > acme_shop.sql

Client databases and users are named <account>_<suffix>; passwords are generated in the panel and never stored in clear.

Files and accounts on disk

ls -la /home/<account>/                 # public_html/, <domain>/, mail/, tmp/, .ssh/
getfacl /home/<account>/public_html     # www-data traverse/read ACLs
sudo -u <account> ls /home/<account>    # what the account itself sees
id <account>; passwd -S <account>       # uid/groups, lock state (L = suspended)
ls /etc/apache2/minipanel/              # one vhost file per domain
cat /var/spool/cron/crontabs/<account>  # rendered crontab

Where things are

Path What
/etc/minipanel/config.toml server settings (root-only)
/var/lib/minipanel/state.db the state database
/var/log/minipanel/audit.log audit log (JSON lines)
/var/backups/minipanel/ backup archives
/var/lib/minipanel/web/, /var/lib/minipanel/admin/ web app session DBs and upload spools
/var/log/apache2/minipanel/<account>/ per-domain web logs
/etc/letsencrypt/live/ certificates
/usr/local/lib/minipanel/ binaries and VERSION

Emergencies

Situation Do
Client locked out of the panel panelctl account passwd NAME (also clears the lockout); 2FA lost → the client uses a recovery code, or you reset with panelctl account passwd and they disable/re-enable 2FA
Admin locked out / lost authenticator panelctl admin passwd NAME, panelctl admin totp-reset NAME
Site 500 after a cPanel migration .htaccess has php_value lines — remove them, use .user.ini
Account shows apply_state failed panelctl account show NAME for the reason, fix, panelctl rebuild --account NAME
Certificate stuck pending_dns every A/AAAA of the domain must point here; panelctl ssl retry DOMAIN
Panel says "Panel unavailable" systemctl status minipaneld, journalctl -u minipaneld
Restore a deleted file for a client panelctl backup restore FILE --account NAME --confirm (replaces the whole home) or hand-extract home/<account>/path from the archive with tar
Server lost fresh install, copy the newest archive to /var/backups/minipanel/, panelctl backup restore FILE --confirm