User Guide
Exact page and CLI steps for operating ZePanel.
# ZePanel End User Guide
This guide explains exactly what to do in the web panel and with each CLI command.
Email hosting and DNS management are intentionally not included.
## Before You Start
1. Point your domain's DNS records to this server outside ZePanel.
2. Install the server stack and initialize ZePanel:
```bash
sudo /opt/zepanel/scripts/install-production.sh panel.example.com
```
3. Save the admin password printed by `initialize`.
4. Open the panel at `https://panel.example.com`.
5. Log in as `admin` with the generated password.
6. Open `/health` and fix any failed checks before creating production sites.
## Web Panel Pages
### Login: `/login`
Use this page to start an admin session.
1. Enter the admin username.
2. Enter the admin password.
3. Click `Login`.
Expected result: the dashboard opens.
If login fails:
1. Confirm `/etc/zepanel/zepanel.conf` contains `[panel] admin_user` and either `admin_password_hash` or `admin_password`.
2. Wait 15 minutes if too many failed attempts were made.
3. Check panel logs with `journalctl -u zepanel.service -f`.
### Dashboard: `/`
Use this page as the main navigation hub.
Click:
- `Sites` to create, disable, enable, delete, or repair site permissions.
- `Databases` to create or delete managed databases.
- `CMS Installer` to install, update, or repair WordPress.
- `Backups` to view and restore backups.
- `SSL` to issue or renew certificates.
- `PHP Versions` to change a site's PHP handler.
- `Services` to view job status and retry or cancel jobs.
- `Health Check` to validate system readiness.
- `Audit Log` to review admin actions.
- `Settings` to change the panel admin password.
### Sites: `/sites`
Use this page to manage Apache sites.
Create a site:
1. Enter `Domain`, for example `example.com`.
2. Enter `Document Root`, for example `/var/www/example.com/public`.
3. Click `Create Site`.
4. Go to `/services` and wait for the `site.create` job to complete.
Disable a site:
1. Find the site in `Managed Sites`.
2. Click `Disable`.
3. Go to `/services` and wait for the `site.disable` job to complete.
Enable a disabled site:
1. Find the disabled site.
2. Click `Enable`.
3. Go to `/services` and wait for the `site.enable` job to complete.
Repair file permissions:
1. Find the site.
2. Click `Repair Permissions`.
3. Go to `/services` and wait for the `site.permissions.repair` job to complete.
Delete a site:
1. Find the site.
2. Type the exact domain into the confirmation box.
3. Check `Remove files` only if you want the document root deleted after backup.
4. Click `Delete`.
5. Go to `/services` and wait for the `site.delete` job to complete.
6. Confirm a backup exists on `/backups`.
Important: deleting a site removes the Apache vhost. If `Remove files` is checked, files are deleted after a site backup is created.
### Databases: `/databases`
Use this page to create and delete managed MariaDB/MySQL databases.
Create a database:
1. Enter `Database`, for example `example_wp`.
2. Enter `User`, for example `example_wp_user`. Leave blank only if you want the username to match the database name.
3. Enter a strong database password.
4. Click `Create Database`.
5. Go to `/services` and wait for the `database.create` job to complete.
Delete a database:
1. Find the database.
2. Type the exact database name into the confirmation box.
3. Click `Delete`.
4. Go to `/services` and wait for the `database.delete` job to complete.
5. Confirm a database backup exists on `/backups`.
Retry a failed database delete:
1. Find the database with status `delete_failed`.
2. Type the exact database name into the confirmation box.
3. Click `Retry Delete`.
4. Go to `/services` and wait for the new delete job to complete.
### CMS Installer: `/cms`
Use this page for WordPress installation and maintenance.
Install WordPress:
1. Create the site first from `/sites`.
2. Select the site from the `Site` list. ZePanel automatically uses that site's saved document root.
3. Leave `Database Mode` set to `Automatic` for the normal install path.
4. Click `Install WordPress`.
5. Go to `/services` and wait for the `cms.wordpress.install` job to complete.
6. Open the domain in a browser and finish WordPress setup.
Automatic database mode creates a new database, database user, and strong random
database password for the WordPress install. The password is stored only in the
queued job payload and written into `wp-config.php`; it is not shown in the UI.
ZePanel also writes Redis object cache constants into `wp-config.php` during
install, using `[redis]` settings or the `ZEPANEL_REDIS_*` environment variables
when present.
Use `Manual` database mode when you want ZePanel to create a database and user
with names you choose:
1. Select `Manual - create database and user entered below`.
2. Enter the database name to create.
3. Enter the database user to create.
4. Enter the database password.
5. Click `Install WordPress`.
Use `Existing` database mode only when you already created the database and user
outside this installer:
1. Select `Existing - use database credentials entered below`.
2. Enter the existing database name.
3. Enter the existing database user.
4. Enter that user's database password.
5. Click `Install WordPress`.
Update WordPress:
1. Enter the domain of an active WordPress site.
2. Click `Update WordPress`.
3. Go to `/services` and wait for the `cms.wordpress.update` job to complete.
4. Review the site in a browser.
Repair WordPress:
1. Enter the domain of an active WordPress site.
2. Click `Repair WordPress`.
3. Go to `/services` and wait for the `cms.wordpress.repair` job to complete.
Clean Redis cache:
1. Select the site whose Redis object cache should be cleaned.
2. Click `Clean Redis Cache`.
2. Go to `/services` and wait for the `cache.redis.clean` job to complete.
Redis cleanup is prefix-based and targets the selected site's generated
`WP_REDIS_PREFIX`. It does not run `FLUSHDB`.
Clean Nginx cache:
1. Click `Clean Nginx Cache`.
2. Go to `/services` and wait for the `cache.nginx.clean` job to complete.
Requirements:
- `wp` or the configured `ZEPANEL_WP_CLI` command must be installed for update and repair.
- `redis-cli` must be installed for Redis cache cleanup.
- `nginx` must be installed and `[nginx] cache_path` or `ZEPANEL_NGINX_CACHE_PATH`
must point at the intended cache directory for Nginx cache cleanup.
- The site must be active in ZePanel.
### Backups: `/backups`
Use this page to create, review, and restore backups.
Create a site backup:
1. Select the site domain in `Create Site Backup`.
2. Click `Create Site Backup`.
3. Go to `/services` and wait for the `backup.site.create` job to complete.
4. Return to `/backups` and confirm a new `site` backup record appears with status `complete`.
Create a database backup:
1. Select the database name in `Create Database Backup`.
2. Click `Create Database Backup`.
3. Go to `/services` and wait for the `backup.database.create` job to complete.
4. Return to `/backups` and confirm a new `database` backup record appears with status `complete`.
Restore a site backup:
1. Find a backup with `Type` set to `site` and `Status` set to `complete`.
2. Use the backup row's `Restore` action, or copy its `ID`.
3. Select or enter the destination domain.
4. Click `Restore`.
5. Go to `/services` and wait for the `backup.site.restore` job to complete.
Restore a database backup:
1. Find a backup with `Type` set to `database` and `Status` set to `complete`.
2. Use the backup row's `Restore` action, or copy its `ID`.
3. Select or enter the destination database name.
4. Click `Restore`.
5. Go to `/services` and wait for the `backup.database.restore` job to complete.
Important: restore jobs create a pre-restore backup first. Site restores replace the destination document root contents with the backup contents, so files not present in the backup are removed.
### SSL: `/ssl`
Use this page to issue and renew Let's Encrypt certificates. DNS is not managed by ZePanel.
Before issuing SSL:
1. Confirm the domain points to this server.
2. Confirm the site is active in `/sites`.
3. Confirm Apache is reachable on port 80.
4. Configure `[ssl] email` in `/etc/zepanel/zepanel.conf` or set `ZEPANEL_SSL_EMAIL`.
Issue SSL:
1. Select the active site domain.
2. Click `Issue SSL`.
3. Go to `/services` and wait for the `ssl.issue` job to complete.
4. Visit `https://DOMAIN` and confirm the certificate works.
Renew all certificates:
1. Click `Renew All`.
2. Go to `/services` and wait for the `ssl.renew` job to complete.
### PHP Versions: `/php`
Use this page to change the PHP handler for an active site.
1. Select the domain.
2. Select the PHP version.
3. Click `Set PHP Version`.
4. Go to `/services` and wait for the `php.set` job to complete.
5. Test the site.
If the job fails:
1. Open `/health`.
2. Confirm the selected PHP-FPM socket exists for PHP 8.1, 8.2, or 8.3.
3. Confirm Apache config validation passes in the job logs.
### Services: `/services`
Use this page to inspect services and manage jobs.
1. Review Apache, MariaDB, and the versioned PHP-FPM services.
2. Review `Recent Jobs`.
3. Click a job ID to open detailed logs.
4. For queued jobs, click `Cancel` if the job should not run.
5. For failed retryable jobs, click `Retry`.
6. Use the status buttons to show only queued, running, complete, failed, or canceled jobs.
7. Use `Next` and `Previous` when older jobs are available.
Job statuses:
- `queued`: waiting for the worker.
- `running`: claimed by the worker.
- `complete`: finished successfully.
- `failed`: stopped with an error.
- `canceled`: canceled before execution.
If jobs do not move:
1. Check worker status: `systemctl status zepanel-worker.service`.
2. Watch worker logs: `journalctl -u zepanel-worker.service -f`.
3. Run one job manually: `cd /opt/zepanel && sudo ./venv/bin/python cli/zepanel.py work-once`.
### Job Detail: `/jobs/{job_id}`
Use this page to troubleshoot one job.
1. Open `/services`.
2. Click the job ID.
3. Read logs from top to bottom.
4. If the job is queued and should not run, click `Cancel Job`.
5. If the job failed and is retryable, click `Retry Job`.
For non-retryable failed jobs, create a new operation after fixing the root cause.
### Health Check: `/health`
Use this page before production use and after system changes.
1. Open `/health`.
2. Review the passing and failing counts.
3. Fix failed config checks in `/etc/zepanel/zepanel.conf`.
4. Fix failed service checks with `systemctl status SERVICE`.
5. Fix missing PHP socket checks by installing/enabling the relevant PHP 8.1, 8.2, or 8.3 FPM service.
6. Reopen `/health` after changes.
### Audit Log: `/audit`
Use this page to review admin actions.
1. Open `/audit`.
2. Review `Actor`, `Action`, `Target`, and `Message`.
3. Use the job ID in `Message` to cross-check `/services` or `/jobs/{job_id}`.
### Settings: `/settings`
Use this page to change the panel admin password and check production cookie status.
Change the admin password:
1. Enter the current admin password.
2. Enter a new password with at least 12 characters.
3. Enter the new password again.
4. Click `Update Password`.
5. Log out and log back in with the new password.
Production status:
1. Confirm `Secure Cookies` is enabled after HTTPS is configured for the panel.
2. If secure cookies are disabled, run `enable-secure-cookies` or rerun the panel proxy installer after TLS certificate files exist.
## CLI Commands
Run all commands from `/opt/zepanel` unless the command path is absolute.
### `initialize`
Creates `/etc/zepanel/zepanel.conf`, creates the OS service user, and prints the panel admin password.
```bash
sudo ./venv/bin/python cli/zepanel.py initialize
```
After running:
1. Save the printed admin password.
2. Confirm `/etc/zepanel/zepanel.conf` exists.
3. Run `configure-database-admin`.
4. Run `migrate`.
5. Start the panel and worker services.
### `configure-database-admin`
Creates or updates the configured panel database account and grants it the privileges needed to create databases, create users, and grant database access.
```bash
sudo ./venv/bin/python cli/zepanel.py configure-database-admin
```
### Production Install Script
Creates the Python virtual environment, installs Python requirements, installs
the LAMP stack, installs Remi PHP-FPM runtimes for supported PHP versions,
installs WP-CLI when available, applies migrations, installs services,
scheduled backups, and the panel reverse proxy. On AlmaLinux/RHEL-like systems
it also installs Apache SSL support and certbot when `dnf` is available.
```bash
sudo /opt/zepanel/scripts/install-production.sh panel.example.com
```
After running:
1. Open `https://panel.example.com`.
2. If TLS was not added, confirm DNS points at the server, install certbot, and rerun `install-panel-proxy.sh`.
3. Open `/settings` and confirm secure cookies and HTTPS enforcement are enabled.
### `install-lamp`
Installs Apache, MariaDB, Nginx, Redis, ModSecurity, and the supported Remi
PHP-FPM runtimes using the project install helpers.
```bash
sudo ./venv/bin/python cli/zepanel.py install-lamp
```
After running:
1. Check Apache: `systemctl status httpd`.
2. Check MariaDB: `systemctl status mariadb`.
3. Check Nginx: `systemctl status nginx`.
4. Check Redis: `systemctl status redis`.
5. Check PHP-FPM: `systemctl status php81-php-fpm php82-php-fpm php83-php-fpm`.
### `install-nginx`
Installs and starts Nginx.
```bash
sudo ./venv/bin/python cli/zepanel.py install-nginx
```
### `install-redis`
Installs and starts Redis.
```bash
sudo ./venv/bin/python cli/zepanel.py install-redis
```
### Sudo helper
Installs the root-owned sudo helper and sudoers allowlist used by the planned
least-privilege worker model.
```bash
sudo /opt/zepanel/scripts/install-sudo-helper.sh
```
Read `SUDO_DESIGN.md` before changing the worker service user.
### `install-modsecurity`
Installs ModSecurity and CRS packages when available from the OS repositories.
```bash
sudo ./venv/bin/python cli/zepanel.py install-modsecurity
```
### Nginx panel proxy
Writes an Nginx panel proxy and creates the default Nginx cache directory.
```bash
sudo /opt/zepanel/scripts/install-nginx-panel-proxy.sh panel.example.com
```
When Apache is already serving public `80/443`, set a non-conflicting listen
address:
```bash
sudo ZEPANEL_NGINX_LISTEN=127.0.0.1:18081 /opt/zepanel/scripts/install-nginx-panel-proxy.sh panel.example.com
```
### `install-php-fpm`
Installs or repairs the supported Remi PHP-FPM runtimes and ZePanel pool files.
```bash
sudo ./venv/bin/python cli/zepanel.py install-php-fpm
```
After running, open `/health` and confirm the PHP-FPM service and socket checks pass.
### `install-profile PROFILE`
Installs a CMS dependency profile.
```bash
sudo ./venv/bin/python cli/zepanel.py install-profile wordpress
```
Use this before installing WordPress if the server does not already have the needed PHP extensions.
### `migrate`
Creates or updates ZePanel SQLite tables.
```bash
./venv/bin/python cli/zepanel.py migrate
```
Run this after code updates and before starting services.
### `create-site DOMAIN DOCROOT`
Queues a site creation job.
```bash
./venv/bin/python cli/zepanel.py create-site example.com /var/www/example.com/public
```
After running:
1. Copy the printed job ID.
2. Run `work-once` or wait for the worker.
3. Check the job in `/services`.
### `disable-site DOMAIN`
Queues a site disable job.
```bash
./venv/bin/python cli/zepanel.py disable-site example.com
```
Use this when you want Apache to stop serving the site without deleting state.
### `enable-site DOMAIN`
Queues a site enable job.
```bash
./venv/bin/python cli/zepanel.py enable-site example.com
```
Use this only for sites currently marked disabled.
### `delete-site DOMAIN [--remove-docroot]`
Queues a site delete job.
```bash
./venv/bin/python cli/zepanel.py delete-site example.com
```
To delete files after backup:
```bash
./venv/bin/python cli/zepanel.py delete-site example.com --remove-docroot
```
After running:
1. Confirm a site backup appears in `/backups`.
2. Confirm the job completes in `/services`.
### `repair-site-permissions DOMAIN`
Queues a permissions repair job.
```bash
sudo ./venv/bin/python cli/zepanel.py repair-site-permissions example.com
```
Use this after manual file uploads, restores, or WordPress updates.
### `create-db DBNAME`
Queues database and database-user creation. The username matches the database name.
```bash
./venv/bin/python cli/zepanel.py create-db example_wp
```
After running:
1. Save the printed database password.
2. Wait for the job to complete.
3. Use the credentials in the CMS installer or application config.
### `delete-db DBNAME`
Queues a database delete job.
```bash
./venv/bin/python cli/zepanel.py delete-db example_wp
```
After running:
1. Confirm a database backup appears in `/backups`.
2. Confirm the job completes in `/services`.
### `create-db-user USER PASSWORD`
Creates a database user directly.
```bash
sudo ./venv/bin/python cli/zepanel.py create-db-user example_user 'STRONG_PASSWORD'
```
Use this only for manual recovery or special cases. Normal database creation should use `create-db` or the web panel.
### `install-wordpress DOMAIN DOCROOT DBNAME USERNAME`
Queues a WordPress install job and prompts for the database password.
```bash
./venv/bin/python cli/zepanel.py install-wordpress example.com /var/www/example.com/public example_wp example_wp_user
```
After running:
1. Enter a strong database password when prompted.
2. Wait for the job to complete.
3. Open the domain in a browser.
4. Complete the WordPress setup screen.
### `issue-ssl DOMAIN`
Queues a Let's Encrypt certificate issue job.
```bash
sudo ./venv/bin/python cli/zepanel.py issue-ssl example.com
```
Before running:
1. Confirm DNS points to the server.
2. Confirm Apache serves the domain on port 80.
3. Confirm `[ssl] email` or `ZEPANEL_SSL_EMAIL` is configured.
### `renew-ssl`
Queues certificate renewal for all managed Certbot certificates.
```bash
sudo ./venv/bin/python cli/zepanel.py renew-ssl
```
Run manually when testing renewals. Production renewal can also be handled by system timers if installed.
### `backup-site DOMAIN`
Queues a manual site files backup for a managed site.
```bash
sudo ./venv/bin/python cli/zepanel.py backup-site example.com
```
After running:
1. Copy the printed job ID.
2. Run `work-once` or confirm `zepanel-worker.service` is running.
3. Open `/jobs/JOB_ID` or `/services` and wait for `backup.site.create` to complete.
4. Open `/backups` and confirm the backup record exists.
### `backup-database DBNAME`
Queues a manual SQL dump backup for a managed database.
```bash
sudo ./venv/bin/python cli/zepanel.py backup-database example_wp
```
After running:
1. Copy the printed job ID.
2. Run `work-once` or confirm `zepanel-worker.service` is running.
3. Open `/jobs/JOB_ID` or `/services` and wait for `backup.database.create` to complete.
4. Open `/backups` and confirm the backup record exists.
### `backup-all`
Queues backups for every visible managed site and database.
```bash
sudo ./venv/bin/python cli/zepanel.py backup-all
```
After running:
1. Confirm the worker is running.
2. Open `/services` and wait for queued backup jobs to complete.
3. Open `/backups` and confirm new records exist.
### `prune-backups`
Deletes backup records and files older than the retention window.
```bash
sudo ./venv/bin/python cli/zepanel.py prune-backups --days 30
```
Use the default retention by omitting `--days`.
### `change-admin-password`
Changes the panel admin password from the CLI.
```bash
sudo ./venv/bin/python cli/zepanel.py change-admin-password
```
After running:
1. Enter and confirm the new password.
2. Log in to the panel with the new password.
### `enable-secure-cookies`
Enables secure cookies after the panel is served only over HTTPS.
```bash
sudo ./venv/bin/python cli/zepanel.py enable-secure-cookies
```
### `restore-site BACKUP_ID DOMAIN`
Queues a site-file restore job.
```bash
sudo ./venv/bin/python cli/zepanel.py restore-site 12 example.com
```
Before running:
1. Confirm backup ID `12` is a complete site backup in `/backups`.
2. Confirm `example.com` exists in ZePanel.
3. Confirm you want files overwritten.
### `restore-database BACKUP_ID DBNAME`
Queues a database restore job.
```bash
sudo ./venv/bin/python cli/zepanel.py restore-database 13 example_wp
```
Before running:
1. Confirm backup ID `13` is a complete database backup in `/backups`.
2. Confirm `example_wp` exists in ZePanel.
3. Confirm you want the SQL imported into that database.
### `work-once`
Claims and runs one queued job.
```bash
sudo ./venv/bin/python cli/zepanel.py work-once
```
Use this for testing or recovery when the worker service is stopped.
### `worker [--poll-interval SECONDS]`
Runs the durable job worker in the foreground.
```bash
sudo ./venv/bin/python cli/zepanel.py worker --poll-interval 2
```
Use systemd for normal production operation. Use this foreground command for troubleshooting.
### `recover-jobs`
Requeues stale retryable jobs and fails stale non-retryable jobs.
```bash
sudo ./venv/bin/python cli/zepanel.py recover-jobs
```
Use this after a worker crash or server reboot if jobs remain stuck in `running`.
### `help-page`
Prints a short CLI help page.
```bash
./venv/bin/python cli/zepanel.py help-page
```
Use `--help` for the full command list:
```bash
./venv/bin/python cli/zepanel.py --help
```
## Common Recovery Steps
If a web action fails:
1. Open `/services`.
2. Click the failed job ID.
3. Read the error log.
4. Fix the missing service, permission, config, or package.
5. Retry only if the job shows a retry button; otherwise create a new operation.
If the panel will not load:
```bash
systemctl status zepanel.service
journalctl -u zepanel.service -n 100 --no-pager
```
If jobs do not run:
```bash
systemctl status zepanel-worker.service
journalctl -u zepanel-worker.service -n 100 --no-pager
```
If SSL fails:
1. Confirm DNS points to this server.
2. Confirm port 80 is reachable.
3. Confirm the site vhost exists and is active.
4. Confirm `certbot` is installed.
5. Confirm `[ssl] email` is configured.
If WordPress update or repair fails:
1. Confirm `wp` is installed or `ZEPANEL_WP_CLI` points to WP-CLI.
2. Confirm the site has `wp-config.php`.
3. Repair permissions.
4. Review the job log.