Open sourceIn the free reqad package (GPL-3.0).
Update scripts
Reqad keeps its maintenance scripts in /usr/local/reqad/scripts/update/. Each one fixes or sets up one thing on an existing server. Most run on their own on every install and update; a few are for you to run when you need them. This page lists them all, so you know which ones have already run and when to run the others.
dnf update reqad runs the automatic ones for you, in the right order. Each checks first and changes nothing when the server is already right, so running one again is harmless. Their output is in /usr/local/reqad/log/post_install.log.Running one by hand
bash /usr/local/reqad/scripts/update/<script> --dry-run bash /usr/local/reqad/scripts/update/<script> --apply
- Run them as root.
- Where a script has
--dry-run, try that first: it shows what would change and changes nothing. - Scripts that edit nginx, Apache, exim, dovecot or PHP-FPM test the new configuration first (
nginx -t,httpd -t,exim -bV,doveconf,php-fpm -t) and put the old file back if the test fails. - The header comment at the top of each script explains why it exists and what it touches.
Run on every install and update
In the order the update runs them. By hand lists the options that are useful when you run one yourself; panel marks scripts the panel also calls when you change the setting they belong to.
Panel, webmail and web server
| Script | What it does | By hand |
|---|---|---|
update_hostname_cert.sh | Makes sure the panel (port 2087, and the account panel on 2083) and the server hostname's default nginx site use a certificate that exists. If the hostname's Let's Encrypt certificate could not be issued (for example port 80 is not reachable from the internet yet, or the DNS record is new), they get a self-signed certificate so the panel still starts; once the Let's Encrypt certificate exists they switch to it. A certificate you set yourself is kept. | --dry-run. Run it after getting the hostname's certificate to switch to it right away. |
setup_reqad_fpm.sh | Sets up the panel's own PHP-FPM master (reqad-php-fpm, with its own php.ini). Runs once; later updates leave it alone, so your changes are kept. | - |
update_ini.sh | Adds missing keys to etc/server-software.ini. Never changes a value you set. | - |
update_roundcube.sh | Updates Roundcube (webmail) to the latest stable release; keeps its config, logs, temp files and custom plugins. Also runs install-webmail-autologin.sh. | Run it to update webmail between Reqad releases. |
install-webmail-autologin.sh | Installs the Roundcube plugin behind the panel's "open webmail" button, and makes webmail send mail signed in as the mailbox, so the server's sending limits apply to webmail too. A sending setting you changed yourself is kept. | Panel: when webmail auto-login is switched on. |
setup_webmail_guard.sh --apply | Webmail brute-force protection: at most 3 failed logins a minute per mailbox, login POSTs limited per IP in nginx, and an lfd rule (tag reqadwebmail) that blocks an IP in the firewall after 10 failed logins. Blocks show under Settings > Security > Blocked addresses. | --dry-run, --remove |
setup_webmail_port.sh | Gives webmail a port of its own, 2096: https://<hostname>:2096/webmail/. Mailbox owners then never need the panel's port 2087, so you can turn on Settings > Security > IP restriction and webmail keeps working for everyone. Only webmail is served on 2096, not the panel. Old links to :2087/webmail/ (and :2083/webmail/ with an up-to-date account panel) go to the new address, the firewall opens port 2096, and every site's /webmail address points there. The "open webmail" buttons in both panels keep signing you in. | --dry-run shows the change, --remove puts webmail back on the panel's port, --no-firewall leaves the firewall alone. |
update_user_phpfpm.sh | Adds required settings (security, logs, temp directories) to every account's PHP-FPM pool. | - |
update_default_nginx_host.sh | Creates the default nginx site for the server hostname if it is missing, with a Let's Encrypt certificate if there is one, otherwise self-signed, and includes the Git deploy webhook address when it is set up. | Panel: when converting Apache to nginx. |
update_certbot_hostname.sh | Renews the hostname certificate through the web server instead of the standalone method. | - |
update_default_apache_host.sh | The same as the nginx one, for Apache servers (skipped when Apache is not installed, or when it runs behind nginx). | - |
update_wetty_shell.sh | Keeps the web terminal (wetty) on Reqad's packaged start script. Does nothing without wetty. | - |
merge_le_ssl_vhosts.sh | Apache servers: when Let's Encrypt was set up on a site that had no https settings yet, certbot kept them in a separate file. This moves them into the site's own settings file, so the panel shows the certificate and its changes (suspension, redirects, PHP settings, removing the site) apply to https too. Websites keep working exactly as before; each site is tested and put back if the test fails. | --dry-run, --domain=<site>. Panel: after getting a Let's Encrypt certificate on Apache. |
| Script | What it does | By hand |
|---|---|---|
setup_autoresponder_sieve.sh | Sets up autoresponders in Sieve. Only acts on servers that deliver mail through dovecot LMTP (see setup_dovecot_sieve.sh below). | - |
setup_sieve_pipe.sh | Enables the "Pipe to a program" email filter action, for server-wide and domain filters only. Same condition as above. | - |
seed_skiprbl_extra.sh | One-time move of a hand-made RBL skip list into the panel's "extra addresses". Does nothing afterwards. | - |
fix_maildir_dotfiles.sh | Keeps dovecot's internal files out of the folder list in mail clients. | - |
fix_imap_separator.sh | Makes sure the IMAP folder separator is ., which matches how mail is stored, and repairs folder subscriptions. | - |
fix_managesieve_listen.sh | ManageSieve listens on IPv4 loopback only, so dovecot starts on servers without IPv6. | - |
setup_special_use.sh | Tells mail clients which folders are Sent, Drafts, Trash and Junk, so phones and webmail use the same ones. | Afterwards see merge_duplicate_sent.sh. |
repair_truncated_exim_conf.sh | Restores a damaged exim configuration from the newest good backup. Does nothing when the configuration is complete. | [path to exim.conf] |
setup_spam_score_logging.sh | One SpamAssassin scan per incoming message as the receiving account, the score in exim's log and X-Spam-* headers on the message. | - |
setup_spamd_per_user.sh | Lets SpamAssassin read each account's own allow and block lists. | - |
setup_exim_reload.sh | Gives exim a real reload, so configuration changes apply without dropping connections. | Panel: used before reloading exim. |
setup_mail_limits.sh | Outgoing limits per sending domain: messages per hour and failed messages per hour. | Panel: Email > Config. |
fix_system_alias_pipe.sh | Delivers mail for root to the panel's root-mail forwarder reliably. | - |
setup_root_mail_log.sh | When root mail forwarding is off, keeps mail sent to root (cron, firewall, monitoring) on the server in /var/log/reqad/root-mail instead of leaving it in the mail queue. The file is readable only by root and the panel, and its size is capped at 10 MB plus one older copy. Settings > System mail shows the last 100 lines. | --dry-run |
setup_forward_spam_gate.sh | Doesn't forward mail SpamAssassin already marked as spam, which protects the server's sending reputation. | Panel: switch in Email > Config. |
setup_exim_remote_domains.sh | Lets a domain's email be handled by another provider (such as Google Workspace, Microsoft 365 or Zoho Mail) while its website stays on this server: mail the server sends to that domain then goes to the provider instead of the mailboxes here, and mail that still arrives here while the change spreads is passed on to the provider or retried, not refused. Only the standard mail server settings are changed. | --dry-run shows the change. Panel: Mail provider in the account panel's DNS zone. |
setup_exim_dbl.sh | Sender domain check: refuses incoming mail when the sender's domain is on the Spamhaus Domain Block List as spam, phishing, malware or botnet, which also stops a spammer who moves to new IP addresses. Real sites that were hacked, bounces, your own users and trusted senders are not refused. It also makes the Spamhaus IP blocklists count only real listings, so a refused DNS resolver can never cause all mail to be rejected. | --on / --off. Panel: Email > Exim > Blocklists. The dashboard warns when Spamhaus does not answer the server's DNS resolver. |
ensure_dovecot_packages.sh | Checks that the dovecot add-on packages match dovecot and that Sieve is installed where it is used. During an update it only reports. | --fix installs what is missing. |
setup_dovecot_compress.sh --repair | Mail compression settings for dovecot 2.4; --repair only fixes a setup that is already on. | --status, --disable. Panel: Email > Config. |
setup_dovecot_vsz.sh --migrate | The memory limit per IMAP/POP3 process, kept in its own file. | --status, --vsz <size>, --reset. Panel: Email > Config. |
setup_autoconfig.sh | Automatic setup of mail accounts in Thunderbird and Outlook (static files, no PHP involved). | Panel: when converting Apache to nginx. |
Security and isolation
| Script | What it does | By hand |
|---|---|---|
patch_csf_cve_2026_67402.sh | Applies the CVE-2026-67402 fix to an installed csf (new installs get a fixed csf). | - |
fix_vhost_deny_order.sh | Puts the "deny hidden files" and "deny PHP in uploads" rules of existing sites before the PHP handler. | --dry-run |
setup_error_pages.sh | Reqad's error pages for every site; the pages don't name the web server software. The web server reads them from /usr/share/reqad/error-pages. | Panel: when converting Apache to nginx. |
setup_directory_index.sh | On servers with Apache, a folder that has both an index.php and an index.html shows the index.php, as it does with nginx. A site can still choose another order with DirectoryIndex in its .htaccess. | --dry-run, --remove |
setup_httpd_home_overrides.sh | On servers with Apache, the public_html folder of every account allows the same .htaccess settings as the sites themselves. An addon domain or subdomain whose folder is inside public_html also reads the main site's .htaccess; before, an Options line there (for example Options -Indexes) made the addon site answer with an error 500. A copy of the old file is kept, and it is put back if Apache does not accept the change. | --dry-run, --remove |
setup_site_file_denies.sh | Sites do not serve hidden files and folders (such as .git or .env) or the instruction files of AI coding assistants (CLAUDE.md, AGENTS.md, GEMINI.md), which answer 404. On nginx the rules go into each site's configuration; on servers with Apache they are in /etc/httpd/conf.d/reqad-site-denies.conf, written once and then left as you change it. Both carry a commented-out alternative that keeps /.well-known/ reachable, for a certificate client other than certbot (certbot adds its own rule while it checks the domain). | --dry-run |
fix_cache_perms.sh | Tightens permissions on the nginx caches and the shared PHP session folder. | - |
fix_letsencrypt_perms.sh | Keeps Let's Encrypt private keys readable only by the server and the mail services, and certificates readable by all. Runs again after every certificate renewal. | --check (only report) |
refresh_wp_security.php | Re-applies WordPress Toolkit security rules to the sites that use them, so rule improvements in an update reach them. When a site has several WordPress installs (for example one in /blog), the rules protect all of them. | Run with the panel's PHP: /opt/reqad/php-current/usr/bin/php -c /etc/reqad/php-fpm/php.ini … |
update_wp_cache_blocks.sh | Brings the WordPress Toolkit page cache of sites that use it up to date, with each site's own cache rules. Links that carry only campaign tags (utm_, gclid, fbclid and similar) are served from the cache, and WordPress sees them without the tags. Sites that are already current are left alone; the previous files are kept in /var/lib/reqad/vhost-backups/. | --dry-run |
fix_panel_ip_bypass.sh | The panel asks every client for its login, and monit checks an nginx-only /reqad-health address instead of the dashboard. | --dry-run |
remove_panel_websocket.sh | Removes an unused web address from the panel that belonged to the old WordPress scan console, which the panel no longer has. Does nothing once it is gone. | --dry-run |
setup_panel_loopback_guard.sh | Firewall rule: code running as a hosting account can't connect to the panel's local ports (panel, web terminal, monit), nor straight to Apache behind nginx, nor to the apps of other accounts. | --dry-run, --remove |
setup_panel_api.sh | Makes the panel's web server send /api/ on port 2087 to the REST API, which accepts access tokens only (never the panel login) and limits how fast one address can call it. The API itself stays off until you turn it on. Other panels on the same web server, such as the account panel on port 2083, keep their own /api/. It also sends /pdns/ to the DNS API, where other servers keep their own DNS zones on this server with a DNS API key; that too stays off until you turn it on. | --dry-run, --remove |
setup_deploy_webhook.sh | Lets GitHub, GitLab, Gitea and Bitbucket start a Git deployment on push, at https://<hostname>/.reqad-deploy/<id>. Only signed requests start a deploy, and the panel port can stay closed to the internet. Needs nginx in front. | --dry-run, --remove |
fix_panel_tree_perms.sh | The panel's folder, database and backups are readable by the panel only, not by hosting accounts. | --dry-run |
fix_dovecot_users_perms.sh | The mailbox password file is readable by the mail server and root only. | --dry-run |
setup_sysctl_hardening.sh | Kernel settings that keep accounts from watching each other (/etc/sysctl.d/90-reqad.conf). Override a value in 99-local.conf. | --dry-run, --remove |
fix_sudo_nsswitch.sh | Stops sudo from looking up its rules in sssd on servers that don't run sssd (many cloud images are set up that way). Without it every sudo call writes a “problem with defaults entries” warning and mails it to root, which fills the mail queue. Servers where sssd is configured are left alone. | --dry-run |
setup_proc_hidepid.sh | Each account sees only its own processes. | --dry-run, --remove |
harden_account_perms.sh --apply --quiet | Account permissions: a site's files readable by its own account and the web server only; PHP pools in the account's own group. Writes a restore script (/var/lib/reqad/perms-restore-<time>.sh) before changing anything. | --dry-run, --user=NAME. Panel: after a PHP handler change and when converting Apache to nginx. |
setup_symlink_protection.sh | Symbolic links: a site can only follow a link to a file with the same owner, so an account cannot link another account's files into its own site. With Apache (PHP-FPM templates), .htaccess files can no longer turn on FollowSymLinks; the ones that ask for it get SymLinksIfOwnerMatch, which rewrite rules accept the same way. Lists the links that will stop working first. | --dry-run, --htaccess (only the .htaccess files), --remove |
tune_fpm_pools.sh --apply | Moves PHP pools still on the old defaults to on-demand workers: up to 20 per site, stopped after 10 s idle, a stuck script ended after 5 minutes. Pools you tuned are left alone. | --dry-run |
setup_session_limits.sh --apply | CPU, memory and process limits for each account's SSH, cron and web terminal sessions, and the log of limit hits. | --dry-run, --remove. Per account: reqad account limits. |
The update also runs three steps from outside this folder: scripts/account_shell.sh install (the jailed shell, for accounts with jailed or SFTP-only access), scripts/account_shell.sh restrict (when root_access=0 is set in server-software.ini, accounts get only the jailed shell or SFTP: one that still has a full shell is moved to the jailed shell and cron jobs run in the sandbox; nothing changes otherwise) and reqad account limits --sync-db --quiet (database connection limits per account).
Run once, when needed
| Script | When the update runs it | What it does |
|---|---|---|
migrate_smtp_errors_log.sh | Updating from a panel database older than 1034. | Moves old SMTP delivery errors from the panel database into log/smtp_errors.log. |
Run by hand
These are never run by an update, because they change how mail is delivered, install packages, or are one-off jobs. Run each one when you need what it does.
| Script | When to run it | Notes |
|---|---|---|
check_lmtp_readiness.sh | Before switching mail delivery to dovecot LMTP. | Only reads. A non-zero exit code means: don't switch yet. setup_dovecot_sieve.sh runs it itself. |
setup_dovecot_sieve.sh | To turn on email filters at all three levels (server, domain, mailbox) and filter editing from webmail and mail clients. | Switches delivery to dovecot LMTP + Sieve and installs packages. --check only reports. See Email filters. |
setup_dovecot_fts.sh | To make mailbox searches fast. | Installs a package, restarts dovecot and indexes every mailbox over time. See Email search & indexing. |
merge_duplicate_sent.sh | Once, after setup_special_use.sh, to merge Apple Mail's "Sent Messages" into "Sent". | Only reports by default; --apply moves the mail. The only script here that moves messages. |
migrate_dovecot_2.4.sh | Upgrading a server from dovecot 2.3 to 2.4. | Rewrites the dovecot configuration and keeps mailboxes, certificates and keys. --no-upgrade, --force. |
rename_hostname.sh | Changing the server's hostname. | <new.host.name> [--dry-run] [--yes] [--no-cert] [--delete-old-cert]. Updates the server's own sites, the certificate (a free one for the new name when it already points to the server), mail, the account panel on port 2083 and its /cpanel links, Git deploy webhooks and the FTP certificate. Copies every file it changes to /root/reqad-hostname-rename-<time>/ first. Moving to a new IP address too? Change the IP first, then the name. |
update_phpmyadmin.sh | To update phpMyAdmin to the latest stable release. | Keeps its configuration and temp folder. |
ensure_dovecot_packages.sh --fix | When an update reported a missing or mismatched dovecot package. | The report-only check runs on every update. |
Need a hand? Create a free account or contact us.