- PHP 82.2%
- JavaScript 14.6%
- CSS 3.2%
- Block reuse of TOTP codes within the same 30s window via last_totp_step tracking - Regenerate session ID after password auth when 2FA is pending - Validate timezone POST input against timezone_identifiers_list() - Remove server filesystem path from Composer missing error message - Bump version to 26.06.04-1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| app | ||
| assets | ||
| vendor | ||
| .gitignore | ||
| composer.json | ||
| composer.lock | ||
| config.example.php | ||
| DEPLOY.md | ||
| index.php | ||
| README.md | ||
MX Admin (MXA)
A lightweight web-based admin panel for iRedMail mail servers. Built as a replacement for iRedAdmin with a focus on simplicity, security, and practical day-to-day mail server management.
Features
- Mailbox management — create, edit, delete users; set quotas; toggle protocols
- Domain management — multiple domain support with per-domain admin delegation
- Forwarding & aliases — forwarding rules, aliases, and catch-all addresses
- Retention policies — auto-delete mail older than N days per domain
- Distribution groups — manage mailing lists
- SOGo integration — calendar/contact sharing; SOGo data cleanup on user delete
- Roundcube integration — orphaned data cleanup on user delete
- Two-factor authentication — TOTP with QR code setup and backup codes
- Audit log — all admin actions logged with IP and timestamp
- IP blocking — automatic permanent IP block after repeated failed logins
- Mail queue monitoring — view Postfix queue status
- Dashboard — recent activity, admin logins, failed login attempts
Requirements
- PHP 8.2+
- MariaDB / MySQL (iRedMail
vmaildatabase schema) - Nginx (iRedMail default — MXA runs as a location block within the existing server)
- iRedMail installed and configured
- PHP extensions:
pdo_mysql,session,hash,openssl
Installation
1. Database user
CREATE USER 'iredadmin'@'127.0.0.1' IDENTIFIED BY 'yourpassword';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, ALTER ON vmail.* TO 'iredadmin'@'127.0.0.1';
GRANT SELECT, INSERT, DELETE ON sogo.* TO 'iredadmin'@'127.0.0.1';
GRANT SELECT, DELETE ON roundcubemail.* TO 'iredadmin'@'127.0.0.1';
FLUSH PRIVILEGES;
2. Config file
mkdir -p /etc/mxa
cp config.example.php /etc/mxa/config.php
chown root:www-data /etc/mxa/config.php
chmod 640 /etc/mxa/config.php
Edit /etc/mxa/config.php and set your database credentials, timezone, and other options. See the Configuration Reference below.
3. Web files
mkdir -p /var/www/mxa
cp -r assets app index.php vendor /var/www/mxa/
chown -R www-data:www-data /var/www/mxa
chmod -R 750 /var/www/mxa
4. Nginx
MXA is designed to run as a /mxa/ location block within an existing iRedMail nginx server — it does not require a separate server block or virtual host.
Create the template file:
vi /etc/nginx/templates/mxa.tmpl
location ^~ /mxa/ {
alias /var/www/mxa/;
index index.php;
# Static assets
location /mxa/assets/ {
expires 30d;
access_log off;
}
# Block direct access to app and vendor directories
location ^~ /mxa/app/ {
deny all;
}
location ^~ /mxa/vendor/ {
deny all;
}
# Only allow index.php to execute as PHP
location ~ \.php$ {
if ($fastcgi_script_name !~ "^/mxa/index\.php$") {
return 404;
}
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass 127.0.0.1:9999;
}
}
# Redirect /mxa → /mxa/
location = /mxa {
return 301 $scheme://$http_host/mxa/;
}
Include it in your iRedMail SSL server block (add before any other includes):
vi /etc/nginx/sites-available/00-default-ssl.conf
include /etc/nginx/templates/mxa.tmpl;
Update security headers in /etc/nginx/templates/hsts.tmpl:
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Reload nginx:
nginx -t && systemctl reload nginx
5. Verify
# app/ and vendor/ must be blocked
curl -I https://mail.example.com/mxa/app/functions.php
# → 403 Forbidden
curl -I https://mail.example.com/mxa/vendor/autoload.php
# → 403 Forbidden
# App should load
curl -I https://mail.example.com/mxa/
# → 200 OK
Configuration Reference
All settings are in /etc/mxa/config.php (outside the web root). See config.example.php for a fully commented template.
| Constant | Default | Description |
|---|---|---|
APP_TITLE |
MX Admin |
Title shown in the browser and UI |
CHANGELOG_URL |
'' |
URL of a changelog HTML file; leave empty to disable update checks |
DB_HOST |
127.0.0.1 |
MariaDB host |
DB_USER |
iredadmin |
MariaDB username |
DB_PASS |
— | MariaDB password |
DB_NAME |
vmail |
iRedMail database name |
VMAIL_BASE |
/var/vmail/vmail1 |
Base path for mail storage |
SESSION_TIMEOUT |
3600 |
Idle session timeout in seconds |
LOGIN_BLOCK_ATTEMPTS |
5 |
Failed logins before IP block (per 15 min window) |
PASSWORD_GEN_LENGTH |
16 |
Length of generated passwords |
DASHBOARD_SHOW_RECENT_ACTIVITY |
1 |
Show recent activity panel (0 to hide) |
APP_TIMEZONE |
UTC |
Timezone for audit log date display |
BEHIND_PROXY |
false |
Set true if behind a trusted nginx reverse proxy |
APP_DIR |
/var/www/mxa/app |
Path to the app/ directory on disk |
Security Notes
config.phpis stored at/etc/mxa/config.php, outside the web root, and never committed to version control.- The
app/directory is denied at the nginx level — onlyindex.phpandassets/are publicly reachable. - Only
index.phpis executed by PHP-FPM; all other.phprequests return 404. - Sessions use HttpOnly, Secure, and SameSite=Lax cookie flags.
- All POST/GET mutations are protected by CSRF tokens.
- IPs are permanently blocked after repeated failed login attempts.
- Passwords are stored in iRedMail's native format (
{BLF-CRYPT}bcrypt or SSHA512). - The database user requires only SELECT/INSERT/UPDATE/DELETE — no SUPER or FILE privileges.
Updating
Replace the files in /var/www/mxa/. The config at /etc/mxa/config.php is never touched by updates.
Dependencies
chillerlan/php-qrcode
chillerlan/php-qrcode — QR code generation for 2FA setup (MIT / Apache 2.0)
The vendor/ directory is included in this repository, so no action is required for a standard install.
If you need to reinstall or update it, run the following from /var/www/mxa/:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --quiet
php -r "unlink('composer-setup.php');"
php composer.phar require chillerlan/php-qrcode
rm composer.phar