feat(mailinabox): Major enhancement to mail server package v2.0.0
Complete rewrite of mailinaboxctl with comprehensive features: Container Management: - install, check, update, status, logs, shell commands - Better prerequisite checking and Docker integration Email Account Management: - user-add/del/list/passwd for email accounts - alias-add/del/list for email aliases - Uses docker-mailserver setup command Domain & SSL: - domain-add/list for virtual domains - ssl-status/renew for certificate management - Let's Encrypt integration Backup & Restore: - Full backup with automatic container stop - Restore with confirmation prompt Diagnostics: - health: comprehensive health check - dns-check: verify MX, SPF, DMARC records - ports: check listening ports - config: show current configuration - test-email: send test message Updated configuration with: - Separate hostname and domain options - Feature flags for ClamAV, SpamAssassin, Fail2ban, POP3 - SSL type selection (letsencrypt, manual, self-signed) - Complete port mapping options Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
13d7e8641f
commit
b671843132
@ -1,8 +1,8 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=secubox-app-mailinabox
|
PKG_NAME:=secubox-app-mailinabox
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=1
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=2.0.0
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||||
PKG_LICENSE:=CC0-1.0
|
PKG_LICENSE:=CC0-1.0
|
||||||
@ -14,14 +14,26 @@ define Package/secubox-app-mailinabox
|
|||||||
CATEGORY:=Utilities
|
CATEGORY:=Utilities
|
||||||
PKGARCH:=all
|
PKGARCH:=all
|
||||||
SUBMENU:=SecuBox Apps
|
SUBMENU:=SecuBox Apps
|
||||||
TITLE:=SecuBox Mail-in-a-Box docker app
|
TITLE:=SecuBox Mail Server (docker-mailserver)
|
||||||
DEPENDS:=+uci +libuci
|
DEPENDS:=+uci +libuci
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/secubox-app-mailinabox/description
|
define Package/secubox-app-mailinabox/description
|
||||||
Installer, configuration, and service manager for running Mail-in-a-Box
|
Complete email server solution using docker-mailserver for SecuBox.
|
||||||
inside Docker on SecuBox-powered OpenWrt systems. Complete email server
|
|
||||||
solution with webmail, calendar, contacts, spam filtering, and DNS.
|
Features:
|
||||||
|
- Full email server (SMTP, IMAP, POP3)
|
||||||
|
- User account management (add/remove/list)
|
||||||
|
- Email aliases support
|
||||||
|
- SpamAssassin spam filtering
|
||||||
|
- ClamAV antivirus (optional)
|
||||||
|
- Fail2ban intrusion prevention
|
||||||
|
- Let's Encrypt SSL certificates
|
||||||
|
- Backup and restore functionality
|
||||||
|
- DNS configuration verification
|
||||||
|
- Health monitoring and diagnostics
|
||||||
|
|
||||||
|
Commands: mailinaboxctl --help
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/secubox-app-mailinabox/conffiles
|
define Package/secubox-app-mailinabox/conffiles
|
||||||
|
|||||||
@ -1,22 +1,30 @@
|
|||||||
config mailinabox 'main'
|
config mailinabox 'main'
|
||||||
option enabled '0'
|
option enabled '0'
|
||||||
option image 'docker-mailserver/docker-mailserver:latest'
|
option image 'ghcr.io/docker-mailserver/docker-mailserver:latest'
|
||||||
option data_path '/srv/mailinabox'
|
option data_path '/srv/mailserver'
|
||||||
|
|
||||||
|
# Domain configuration (MUST be configured before use)
|
||||||
option hostname 'mail.example.com'
|
option hostname 'mail.example.com'
|
||||||
option admin_email 'admin@example.com'
|
option domain 'example.com'
|
||||||
option timezone 'UTC'
|
option timezone 'UTC'
|
||||||
|
|
||||||
# Port mappings
|
# Port mappings
|
||||||
option smtp_port '25'
|
option smtp_port '25'
|
||||||
option dns_port '53'
|
|
||||||
option http_port '80'
|
|
||||||
option https_port '443'
|
|
||||||
option submission_port '587'
|
option submission_port '587'
|
||||||
|
option submissions_port '465'
|
||||||
|
option imap_port '143'
|
||||||
option imaps_port '993'
|
option imaps_port '993'
|
||||||
|
option pop3_port '110'
|
||||||
option pop3s_port '995'
|
option pop3s_port '995'
|
||||||
option sieve_port '4190'
|
|
||||||
|
|
||||||
# Feature flags
|
# Feature flags
|
||||||
option enable_dns '1'
|
option enable_pop3 '0'
|
||||||
option enable_webmail '1'
|
option enable_clamav '0'
|
||||||
option letsencrypt '1'
|
option enable_spamassassin '1'
|
||||||
|
option enable_fail2ban '1'
|
||||||
|
|
||||||
|
# SSL configuration
|
||||||
|
# Options: letsencrypt, manual, self-signed
|
||||||
|
option ssl_type 'letsencrypt'
|
||||||
|
# Email for Let's Encrypt notifications (optional but recommended)
|
||||||
|
#option letsencrypt_email 'admin@example.com'
|
||||||
|
|||||||
@ -4,12 +4,26 @@ START=95
|
|||||||
STOP=10
|
STOP=10
|
||||||
USE_PROCD=1
|
USE_PROCD=1
|
||||||
|
|
||||||
|
EXTRA_COMMANDS="status"
|
||||||
|
EXTRA_HELP=" status Show mail server status"
|
||||||
|
|
||||||
SERVICE_BIN="/usr/sbin/mailinaboxctl"
|
SERVICE_BIN="/usr/sbin/mailinaboxctl"
|
||||||
|
|
||||||
start_service() {
|
start_service() {
|
||||||
|
local enabled
|
||||||
|
config_load mailinabox
|
||||||
|
config_get enabled main enabled 0
|
||||||
|
|
||||||
|
[ "$enabled" != "1" ] && {
|
||||||
|
echo "Mail server is disabled. Enable with: uci set mailinabox.main.enabled=1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
procd_open_instance
|
procd_open_instance
|
||||||
procd_set_param command "$SERVICE_BIN" service-run
|
procd_set_param command "$SERVICE_BIN" service-run
|
||||||
procd_set_param respawn 3600 5 5
|
procd_set_param respawn 3600 5 5
|
||||||
|
procd_set_param stdout 1
|
||||||
|
procd_set_param stderr 1
|
||||||
procd_close_instance
|
procd_close_instance
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,5 +33,10 @@ stop_service() {
|
|||||||
|
|
||||||
restart_service() {
|
restart_service() {
|
||||||
stop_service
|
stop_service
|
||||||
|
sleep 2
|
||||||
start_service
|
start_service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status() {
|
||||||
|
"$SERVICE_BIN" status
|
||||||
|
}
|
||||||
|
|||||||
@ -1,68 +1,116 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SecuBox Mail-in-a-Box manager
|
# SecuBox Mail-in-a-Box manager - Docker Mailserver Edition
|
||||||
|
# Copyright (C) 2024 CyberMind.fr
|
||||||
|
#
|
||||||
|
# Based on docker-mailserver for lightweight email hosting
|
||||||
|
|
||||||
CONFIG="mailinabox"
|
CONFIG="mailinabox"
|
||||||
CONTAINER="secbx-mailinabox"
|
CONTAINER_NAME="secbx-mailserver"
|
||||||
OPKG_UPDATED=0
|
OPKG_UPDATED=0
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
DATA_BASE="/srv/mailserver"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'USAGE'
|
cat <<'EOF'
|
||||||
Usage: mailinaboxctl <command>
|
Usage: mailinaboxctl <command>
|
||||||
|
|
||||||
Commands:
|
Container Management:
|
||||||
install Install prerequisites, prepare directories, pull image
|
install Install prerequisites, prepare directories, pull image
|
||||||
check Run prerequisite checks
|
check Run prerequisite checks (ports, DNS, storage)
|
||||||
update Pull new image and restart
|
update Pull new image and restart
|
||||||
status Show container status
|
status Show container and service status
|
||||||
logs Show container logs (use -f to follow)
|
logs Show container logs (use -f to follow)
|
||||||
admin Open admin interface in browser (shows URL)
|
shell Open shell in container
|
||||||
service-run Internal: run container via procd
|
service-run Internal: run container via procd
|
||||||
service-stop Stop container
|
service-stop Stop container
|
||||||
|
|
||||||
Post-Installation:
|
Email Account Management:
|
||||||
1. Configure hostname and admin_email in /etc/config/mailinabox
|
user-add <email> [password] Add email account
|
||||||
2. Ensure proper DNS configuration (A, MX, SPF, DKIM, DMARC records)
|
user-del <email> Remove email account
|
||||||
3. Start with: /etc/init.d/mailinabox start
|
user-list List all email accounts
|
||||||
4. Access admin panel at https://your-hostname/admin
|
user-passwd <email> Change user password
|
||||||
|
alias-add <alias> <target> Add email alias
|
||||||
|
alias-del <alias> Remove email alias
|
||||||
|
alias-list List all aliases
|
||||||
|
|
||||||
Important Notes:
|
Domain & SSL:
|
||||||
- Requires public IP and proper DNS configuration
|
domain-add <domain> Add email domain
|
||||||
- Port 25 must be open (some ISPs block it)
|
domain-list List configured domains
|
||||||
- Valid domain name required for SSL certificates
|
ssl-status Show SSL certificate status
|
||||||
- Initial setup may take 10-15 minutes
|
ssl-renew Force SSL certificate renewal
|
||||||
USAGE
|
|
||||||
|
Backup & Restore:
|
||||||
|
backup [path] Backup mail data and config
|
||||||
|
restore <backup-file> Restore from backup
|
||||||
|
|
||||||
|
Diagnostics:
|
||||||
|
health Run health checks
|
||||||
|
dns-check [domain] Verify DNS records for domain
|
||||||
|
ports Check required ports
|
||||||
|
config Show current configuration
|
||||||
|
test-email <to> Send test email
|
||||||
|
|
||||||
|
Post-Installation:
|
||||||
|
1. Configure hostname and domain in /etc/config/mailinabox
|
||||||
|
2. Set proper DNS records (A, MX, SPF, DKIM, DMARC)
|
||||||
|
3. Start with: /etc/init.d/mailinabox start
|
||||||
|
4. Add users with: mailinaboxctl user-add admin@yourdomain.com
|
||||||
|
|
||||||
|
Required DNS Records:
|
||||||
|
A mail.domain.com -> your-public-ip
|
||||||
|
MX domain.com -> mail.domain.com (priority 10)
|
||||||
|
TXT domain.com -> "v=spf1 mx -all"
|
||||||
|
TXT _dmarc.domain.com -> "v=DMARC1; p=quarantine"
|
||||||
|
TXT mail._domainkey.domain.com -> (DKIM key from container)
|
||||||
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
require_root() { [ "$(id -u)" -eq 0 ]; }
|
require_root() { [ "$(id -u)" -eq 0 ] || { echo "Root required" >&2; exit 1; }; }
|
||||||
|
|
||||||
|
log_info() { echo "[INFO] $*"; }
|
||||||
|
log_warn() { echo "[WARN] $*" >&2; }
|
||||||
|
log_error() { echo "[ERROR] $*" >&2; }
|
||||||
|
|
||||||
uci_get() { uci -q get ${CONFIG}.main.$1; }
|
uci_get() { uci -q get ${CONFIG}.main.$1; }
|
||||||
|
uci_set() { uci set ${CONFIG}.main.$1="$2" && uci commit ${CONFIG}; }
|
||||||
|
|
||||||
defaults() {
|
# Load configuration with defaults
|
||||||
image="$(uci_get image || echo docker-mailserver/docker-mailserver:latest)"
|
load_config() {
|
||||||
data_path="$(uci_get data_path || echo /srv/mailinabox)"
|
enabled="$(uci_get enabled || echo 0)"
|
||||||
|
image="$(uci_get image || echo ghcr.io/docker-mailserver/docker-mailserver:latest)"
|
||||||
|
data_path="$(uci_get data_path || echo /srv/mailserver)"
|
||||||
hostname="$(uci_get hostname || echo mail.example.com)"
|
hostname="$(uci_get hostname || echo mail.example.com)"
|
||||||
admin_email="$(uci_get admin_email || echo admin@example.com)"
|
domain="$(uci_get domain || echo example.com)"
|
||||||
timezone="$(uci_get timezone || echo UTC)"
|
timezone="$(uci_get timezone || cat /etc/TZ 2>/dev/null || echo UTC)"
|
||||||
|
|
||||||
|
# Ports
|
||||||
smtp_port="$(uci_get smtp_port || echo 25)"
|
smtp_port="$(uci_get smtp_port || echo 25)"
|
||||||
dns_port="$(uci_get dns_port || echo 53)"
|
|
||||||
http_port="$(uci_get http_port || echo 80)"
|
|
||||||
https_port="$(uci_get https_port || echo 443)"
|
|
||||||
submission_port="$(uci_get submission_port || echo 587)"
|
submission_port="$(uci_get submission_port || echo 587)"
|
||||||
|
submissions_port="$(uci_get submissions_port || echo 465)"
|
||||||
|
imap_port="$(uci_get imap_port || echo 143)"
|
||||||
imaps_port="$(uci_get imaps_port || echo 993)"
|
imaps_port="$(uci_get imaps_port || echo 993)"
|
||||||
|
pop3_port="$(uci_get pop3_port || echo 110)"
|
||||||
pop3s_port="$(uci_get pop3s_port || echo 995)"
|
pop3s_port="$(uci_get pop3s_port || echo 995)"
|
||||||
sieve_port="$(uci_get sieve_port || echo 4190)"
|
|
||||||
|
|
||||||
enable_dns="$(uci_get enable_dns || echo 1)"
|
# Features
|
||||||
enable_webmail="$(uci_get enable_webmail || echo 1)"
|
enable_pop3="$(uci_get enable_pop3 || echo 0)"
|
||||||
letsencrypt="$(uci_get letsencrypt || echo 1)"
|
enable_clamav="$(uci_get enable_clamav || echo 0)"
|
||||||
|
enable_spamassassin="$(uci_get enable_spamassassin || echo 1)"
|
||||||
|
enable_fail2ban="$(uci_get enable_fail2ban || echo 1)"
|
||||||
|
ssl_type="$(uci_get ssl_type || echo letsencrypt)"
|
||||||
|
letsencrypt_email="$(uci_get letsencrypt_email)"
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
|
ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Docker Functions
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
ensure_packages() {
|
ensure_packages() {
|
||||||
for pkg in "$@"; do
|
for pkg in "$@"; do
|
||||||
if ! opkg status "$pkg" >/dev/null 2>&1; then
|
if ! opkg list-installed 2>/dev/null | grep -q "^$pkg "; then
|
||||||
if [ "$OPKG_UPDATED" -eq 0 ]; then
|
if [ "$OPKG_UPDATED" -eq 0 ]; then
|
||||||
opkg update || return 1
|
opkg update || return 1
|
||||||
OPKG_UPDATED=1
|
OPKG_UPDATED=1
|
||||||
@ -72,135 +120,553 @@ ensure_packages() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
docker_ready() {
|
||||||
|
command -v docker >/dev/null 2>&1 && [ -S /var/run/docker.sock ]
|
||||||
|
}
|
||||||
|
|
||||||
check_prereqs() {
|
check_prereqs() {
|
||||||
defaults
|
load_config
|
||||||
|
log_info "Checking prerequisites..."
|
||||||
|
|
||||||
# Check hostname configuration
|
# Check hostname configuration
|
||||||
if [ "$hostname" = "mail.example.com" ]; then
|
if [ "$hostname" = "mail.example.com" ] || [ "$domain" = "example.com" ]; then
|
||||||
echo "[WARNING] Please configure hostname in /etc/config/mailinabox" >&2
|
log_warn "Please configure hostname and domain in /etc/config/mailinabox"
|
||||||
echo "[WARNING] Mail-in-a-Box requires a valid domain name" >&2
|
log_warn "docker-mailserver requires a valid domain name"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check cgroups
|
||||||
|
[ -d /sys/fs/cgroup ] || { log_error "/sys/fs/cgroup missing"; return 1; }
|
||||||
|
|
||||||
|
# Install Docker
|
||||||
|
ensure_packages dockerd docker containerd || return 1
|
||||||
|
|
||||||
|
# Enable and start Docker
|
||||||
|
/etc/init.d/dockerd enable >/dev/null 2>&1
|
||||||
|
if ! /etc/init.d/dockerd status >/dev/null 2>&1; then
|
||||||
|
/etc/init.d/dockerd start || return 1
|
||||||
|
sleep 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait for Docker socket
|
||||||
|
local retry=0
|
||||||
|
while [ ! -S /var/run/docker.sock ] && [ $retry -lt 30 ]; do
|
||||||
|
sleep 1
|
||||||
|
retry=$((retry + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -S /var/run/docker.sock ] || { log_error "Docker socket not available"; return 1; }
|
||||||
|
|
||||||
# Create data directories
|
# Create data directories
|
||||||
ensure_dir "$data_path"
|
ensure_dir "$data_path"
|
||||||
ensure_dir "$data_path/mail"
|
ensure_dir "$data_path/mail-data"
|
||||||
ensure_dir "$data_path/ssl"
|
ensure_dir "$data_path/mail-state"
|
||||||
ensure_dir "$data_path/data"
|
ensure_dir "$data_path/mail-logs"
|
||||||
ensure_dir "$data_path/dns"
|
ensure_dir "$data_path/config"
|
||||||
|
|
||||||
# Check system requirements
|
log_info "Docker ready, directories created"
|
||||||
[ -d /sys/fs/cgroup ] || { echo "[ERROR] /sys/fs/cgroup missing" >&2; return 1; }
|
return 0
|
||||||
|
|
||||||
# Install Docker
|
|
||||||
ensure_packages dockerd docker containerd
|
|
||||||
/etc/init.d/dockerd enable >/dev/null 2>&1
|
|
||||||
/etc/init.d/dockerd start >/dev/null 2>&1
|
|
||||||
|
|
||||||
# Port conflict checks
|
|
||||||
if [ "$smtp_port" = "25" ]; then
|
|
||||||
if netstat -tln 2>/dev/null | grep -q ":25 "; then
|
|
||||||
echo "[WARNING] Port 25 already in use - potential conflict" >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$dns_port" = "53" ] && [ "$enable_dns" = "1" ]; then
|
|
||||||
if netstat -uln 2>/dev/null | grep -q ":53 "; then
|
|
||||||
echo "[WARNING] Port 53 already in use - DNS may conflict with dnsmasq" >&2
|
|
||||||
echo "[WARNING] Consider disabling Mail-in-a-Box DNS or moving dnsmasq" >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pull_image() { defaults; docker pull "$image"; }
|
pull_image() {
|
||||||
|
load_config
|
||||||
|
log_info "Pulling Docker image: $image"
|
||||||
|
docker pull "$image"
|
||||||
|
}
|
||||||
|
|
||||||
stop_container() {
|
stop_container() {
|
||||||
docker stop "$CONTAINER" >/dev/null 2>&1 || true
|
docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||||
docker rm "$CONTAINER" >/dev/null 2>&1 || true
|
docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
container_running() {
|
||||||
|
docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute setup.sh in container
|
||||||
|
docker_setup() {
|
||||||
|
if ! container_running; then
|
||||||
|
log_error "Container not running. Start with: /etc/init.d/mailinabox start"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
docker exec -it "$CONTAINER_NAME" setup "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# User Management Commands
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
cmd_user_add() {
|
||||||
|
local email="$1"
|
||||||
|
local password="$2"
|
||||||
|
|
||||||
|
[ -z "$email" ] && { log_error "Usage: mailinaboxctl user-add <email> [password]"; return 1; }
|
||||||
|
|
||||||
|
if [ -n "$password" ]; then
|
||||||
|
docker_setup email add "$email" "$password"
|
||||||
|
else
|
||||||
|
docker_setup email add "$email"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_user_del() {
|
||||||
|
local email="$1"
|
||||||
|
[ -z "$email" ] && { log_error "Usage: mailinaboxctl user-del <email>"; return 1; }
|
||||||
|
docker_setup email del "$email"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_user_list() {
|
||||||
|
docker_setup email list
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_user_passwd() {
|
||||||
|
local email="$1"
|
||||||
|
[ -z "$email" ] && { log_error "Usage: mailinaboxctl user-passwd <email>"; return 1; }
|
||||||
|
docker_setup email update "$email"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_alias_add() {
|
||||||
|
local alias="$1"
|
||||||
|
local target="$2"
|
||||||
|
[ -z "$alias" ] || [ -z "$target" ] && { log_error "Usage: mailinaboxctl alias-add <alias> <target>"; return 1; }
|
||||||
|
docker_setup alias add "$alias" "$target"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_alias_del() {
|
||||||
|
local alias="$1"
|
||||||
|
[ -z "$alias" ] && { log_error "Usage: mailinaboxctl alias-del <alias>"; return 1; }
|
||||||
|
docker_setup alias del "$alias"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_alias_list() {
|
||||||
|
docker_setup alias list
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Domain & SSL Commands
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
cmd_domain_add() {
|
||||||
|
local domain="$1"
|
||||||
|
[ -z "$domain" ] && { log_error "Usage: mailinaboxctl domain-add <domain>"; return 1; }
|
||||||
|
|
||||||
|
# Create virtual domain entry
|
||||||
|
load_config
|
||||||
|
local vhost_file="$data_path/config/postfix-virtual.cf"
|
||||||
|
if ! grep -q "^$domain" "$vhost_file" 2>/dev/null; then
|
||||||
|
echo "$domain" >> "$vhost_file"
|
||||||
|
log_info "Domain $domain added. Restart service to apply."
|
||||||
|
else
|
||||||
|
log_warn "Domain $domain already exists"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_domain_list() {
|
||||||
|
load_config
|
||||||
|
log_info "Configured domains:"
|
||||||
|
if [ -f "$data_path/config/postfix-virtual.cf" ]; then
|
||||||
|
cat "$data_path/config/postfix-virtual.cf" | grep -v "^#" | grep -v "^$"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "Primary domain: $domain"
|
||||||
|
echo "Mail hostname: $hostname"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_ssl_status() {
|
||||||
|
load_config
|
||||||
|
log_info "SSL Configuration:"
|
||||||
|
echo " Type: $ssl_type"
|
||||||
|
|
||||||
|
if container_running; then
|
||||||
|
docker_setup debug show-mail-logs | grep -i "ssl\|cert\|tls" | tail -20
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check certificate files
|
||||||
|
if [ -d "$data_path/config/ssl" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Certificate files:"
|
||||||
|
ls -la "$data_path/config/ssl/" 2>/dev/null || echo " No certificates found"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_ssl_renew() {
|
||||||
|
load_config
|
||||||
|
if [ "$ssl_type" = "letsencrypt" ]; then
|
||||||
|
log_info "Triggering Let's Encrypt renewal..."
|
||||||
|
if container_running; then
|
||||||
|
docker exec "$CONTAINER_NAME" certbot renew
|
||||||
|
else
|
||||||
|
log_error "Container not running"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warn "SSL type is not letsencrypt"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Backup & Restore Commands
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
cmd_backup() {
|
||||||
|
require_root
|
||||||
|
load_config
|
||||||
|
|
||||||
|
local backup_path="${1:-/tmp}"
|
||||||
|
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||||
|
local backup_file="$backup_path/mailserver_backup_$timestamp.tar.gz"
|
||||||
|
|
||||||
|
log_info "Creating backup..."
|
||||||
|
|
||||||
|
# Stop container for consistent backup
|
||||||
|
local was_running=0
|
||||||
|
if container_running; then
|
||||||
|
was_running=1
|
||||||
|
log_info "Stopping container for backup..."
|
||||||
|
stop_container
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create backup
|
||||||
|
tar czf "$backup_file" -C "$(dirname $data_path)" "$(basename $data_path)" 2>/dev/null || {
|
||||||
|
log_error "Backup failed"
|
||||||
|
[ $was_running -eq 1 ] && /etc/init.d/mailinabox start
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restart if was running
|
||||||
|
[ $was_running -eq 1 ] && /etc/init.d/mailinabox start
|
||||||
|
|
||||||
|
log_info "Backup created: $backup_file"
|
||||||
|
ls -lh "$backup_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_restore() {
|
||||||
|
require_root
|
||||||
|
load_config
|
||||||
|
|
||||||
|
local backup_file="$1"
|
||||||
|
[ -z "$backup_file" ] || [ ! -f "$backup_file" ] && {
|
||||||
|
log_error "Usage: mailinaboxctl restore <backup-file>"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn "This will OVERWRITE existing mail data!"
|
||||||
|
echo -n "Continue? [y/N] "
|
||||||
|
read answer
|
||||||
|
[ "$answer" != "y" ] && [ "$answer" != "Y" ] && { echo "Aborted"; return 1; }
|
||||||
|
|
||||||
|
# Stop container
|
||||||
|
if container_running; then
|
||||||
|
log_info "Stopping container..."
|
||||||
|
stop_container
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove existing data
|
||||||
|
log_info "Removing existing data..."
|
||||||
|
rm -rf "$data_path"
|
||||||
|
|
||||||
|
# Restore
|
||||||
|
log_info "Restoring from backup..."
|
||||||
|
tar xzf "$backup_file" -C "$(dirname $data_path)" || {
|
||||||
|
log_error "Restore failed"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info "Restore complete. Start service with: /etc/init.d/mailinabox start"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Diagnostic Commands
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
cmd_health() {
|
||||||
|
load_config
|
||||||
|
|
||||||
|
echo "=== Mail Server Health Check ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Container status
|
||||||
|
echo "Container Status:"
|
||||||
|
if container_running; then
|
||||||
|
echo " [OK] Container is running"
|
||||||
|
local uptime=$(docker inspect --format='{{.State.StartedAt}}' "$CONTAINER_NAME" 2>/dev/null)
|
||||||
|
echo " Started: $uptime"
|
||||||
|
else
|
||||||
|
echo " [FAIL] Container is not running"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Port checks
|
||||||
|
echo "Port Status:"
|
||||||
|
for port in $smtp_port $submission_port $imaps_port; do
|
||||||
|
if netstat -tln 2>/dev/null | grep -q ":$port "; then
|
||||||
|
echo " [OK] Port $port is listening"
|
||||||
|
else
|
||||||
|
echo " [WARN] Port $port is not listening"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Service checks inside container
|
||||||
|
if container_running; then
|
||||||
|
echo "Services Status:"
|
||||||
|
docker exec "$CONTAINER_NAME" supervisorctl status 2>/dev/null || echo " Unable to check services"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Disk usage
|
||||||
|
echo "Disk Usage:"
|
||||||
|
if [ -d "$data_path" ]; then
|
||||||
|
du -sh "$data_path" 2>/dev/null
|
||||||
|
du -sh "$data_path"/* 2>/dev/null | head -10
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_dns_check() {
|
||||||
|
load_config
|
||||||
|
local check_domain="${1:-$domain}"
|
||||||
|
|
||||||
|
echo "=== DNS Check for $check_domain ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# A record
|
||||||
|
echo "A Record (mail.$check_domain):"
|
||||||
|
local a_record=$(nslookup "mail.$check_domain" 2>/dev/null | grep -A1 "Name:" | tail -1)
|
||||||
|
if [ -n "$a_record" ]; then
|
||||||
|
echo " [OK] $a_record"
|
||||||
|
else
|
||||||
|
echo " [FAIL] No A record found"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# MX record
|
||||||
|
echo "MX Record ($check_domain):"
|
||||||
|
local mx_record=$(nslookup -type=mx "$check_domain" 2>/dev/null | grep "mail exchanger")
|
||||||
|
if [ -n "$mx_record" ]; then
|
||||||
|
echo " [OK] $mx_record"
|
||||||
|
else
|
||||||
|
echo " [FAIL] No MX record found"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# SPF record
|
||||||
|
echo "SPF Record ($check_domain):"
|
||||||
|
local spf=$(nslookup -type=txt "$check_domain" 2>/dev/null | grep "v=spf1")
|
||||||
|
if [ -n "$spf" ]; then
|
||||||
|
echo " [OK] $spf"
|
||||||
|
else
|
||||||
|
echo " [WARN] No SPF record found"
|
||||||
|
echo " Recommended: \"v=spf1 mx -all\""
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# DMARC record
|
||||||
|
echo "DMARC Record (_dmarc.$check_domain):"
|
||||||
|
local dmarc=$(nslookup -type=txt "_dmarc.$check_domain" 2>/dev/null | grep "v=DMARC1")
|
||||||
|
if [ -n "$dmarc" ]; then
|
||||||
|
echo " [OK] $dmarc"
|
||||||
|
else
|
||||||
|
echo " [WARN] No DMARC record found"
|
||||||
|
echo " Recommended: \"v=DMARC1; p=quarantine; rua=mailto:postmaster@$check_domain\""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_ports() {
|
||||||
|
load_config
|
||||||
|
|
||||||
|
echo "=== Port Status ==="
|
||||||
|
echo ""
|
||||||
|
echo "Required ports for mail server:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local ports="25:SMTP 587:Submission 465:SMTPS 143:IMAP 993:IMAPS"
|
||||||
|
[ "$enable_pop3" = "1" ] && ports="$ports 110:POP3 995:POP3S"
|
||||||
|
|
||||||
|
for entry in $ports; do
|
||||||
|
local port=$(echo "$entry" | cut -d: -f1)
|
||||||
|
local name=$(echo "$entry" | cut -d: -f2)
|
||||||
|
|
||||||
|
printf " %-6s %-12s " "$port" "$name"
|
||||||
|
|
||||||
|
if netstat -tln 2>/dev/null | grep -q ":$port "; then
|
||||||
|
echo "[LISTENING]"
|
||||||
|
else
|
||||||
|
echo "[NOT LISTENING]"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Note: Port 25 may be blocked by some ISPs"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_config() {
|
||||||
|
load_config
|
||||||
|
|
||||||
|
echo "=== Mail Server Configuration ==="
|
||||||
|
echo ""
|
||||||
|
echo "General:"
|
||||||
|
echo " Enabled: $enabled"
|
||||||
|
echo " Image: $image"
|
||||||
|
echo " Hostname: $hostname"
|
||||||
|
echo " Domain: $domain"
|
||||||
|
echo " Data path: $data_path"
|
||||||
|
echo " Timezone: $timezone"
|
||||||
|
echo ""
|
||||||
|
echo "Features:"
|
||||||
|
echo " SpamAssassin: $enable_spamassassin"
|
||||||
|
echo " ClamAV: $enable_clamav"
|
||||||
|
echo " Fail2ban: $enable_fail2ban"
|
||||||
|
echo " POP3: $enable_pop3"
|
||||||
|
echo " SSL Type: $ssl_type"
|
||||||
|
echo ""
|
||||||
|
echo "Ports:"
|
||||||
|
echo " SMTP: $smtp_port"
|
||||||
|
echo " Submission: $submission_port"
|
||||||
|
echo " IMAPS: $imaps_port"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_test_email() {
|
||||||
|
local to="$1"
|
||||||
|
[ -z "$to" ] && { log_error "Usage: mailinaboxctl test-email <to-address>"; return 1; }
|
||||||
|
|
||||||
|
load_config
|
||||||
|
|
||||||
|
if ! container_running; then
|
||||||
|
log_error "Container not running"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Sending test email to $to..."
|
||||||
|
docker exec "$CONTAINER_NAME" sh -c "echo 'Test email from SecuBox Mail Server' | mail -s 'Test from $hostname' $to"
|
||||||
|
|
||||||
|
log_info "Test email sent (check spam folder if not received)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Main Container Commands
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
cmd_install() {
|
cmd_install() {
|
||||||
require_root || { echo Root required >&2; exit 1; }
|
require_root
|
||||||
check_prereqs || exit 1
|
check_prereqs || exit 1
|
||||||
pull_image || exit 1
|
pull_image || exit 1
|
||||||
uci set ${CONFIG}.main.enabled='1'
|
|
||||||
|
uci_set enabled '1'
|
||||||
uci commit ${CONFIG}
|
uci commit ${CONFIG}
|
||||||
/etc/init.d/mailinabox enable
|
/etc/init.d/mailinabox enable
|
||||||
|
|
||||||
|
load_config
|
||||||
echo ""
|
echo ""
|
||||||
echo "Mail-in-a-Box prerequisites installed."
|
log_info "Mail server installed successfully!"
|
||||||
echo ""
|
echo ""
|
||||||
echo "CRITICAL NEXT STEPS:"
|
echo "NEXT STEPS:"
|
||||||
echo " 1. Edit /etc/config/mailinabox and set:"
|
echo " 1. Edit /etc/config/mailinabox and configure:"
|
||||||
echo " - hostname (must be a valid FQDN)"
|
echo " - hostname (e.g., mail.yourdomain.com)"
|
||||||
echo " - admin_email"
|
echo " - domain (e.g., yourdomain.com)"
|
||||||
echo " 2. Configure DNS records for your domain:"
|
echo " 2. Set up DNS records (see 'mailinaboxctl dns-check')"
|
||||||
echo " - A record: $hostname -> your-public-ip"
|
echo " 3. Start: /etc/init.d/mailinabox start"
|
||||||
echo " - MX record: @ -> $hostname"
|
echo " 4. Add first user: mailinaboxctl user-add admin@$domain"
|
||||||
echo " 3. Ensure port 25 is not blocked by your ISP"
|
|
||||||
echo " 4. Start with: /etc/init.d/mailinabox start"
|
|
||||||
echo " 5. Access admin at: https://$hostname/admin"
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_check() {
|
cmd_check() {
|
||||||
check_prereqs
|
check_prereqs
|
||||||
echo "Prerequisite check completed."
|
|
||||||
echo ""
|
echo ""
|
||||||
defaults
|
cmd_config
|
||||||
echo "Current configuration:"
|
|
||||||
echo " Hostname: $hostname"
|
|
||||||
echo " Admin email: $admin_email"
|
|
||||||
echo " Data path: $data_path"
|
|
||||||
echo " DNS enabled: $enable_dns"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
cmd_ports
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_update() {
|
cmd_update() {
|
||||||
require_root || { echo Root required >&2; exit 1; }
|
require_root
|
||||||
pull_image || exit 1
|
pull_image || exit 1
|
||||||
/etc/init.d/mailinabox restart
|
|
||||||
|
if container_running; then
|
||||||
|
/etc/init.d/mailinabox restart
|
||||||
|
else
|
||||||
|
log_info "Image updated. Start manually when ready."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_status() { docker ps -a --filter "name=$CONTAINER"; }
|
cmd_status() {
|
||||||
|
echo "=== Container Status ==="
|
||||||
cmd_logs() { docker logs "$@" "$CONTAINER"; }
|
docker ps -a --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
|
||||||
cmd_admin() {
|
|
||||||
defaults
|
|
||||||
echo "Admin interface: https://$hostname/admin"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "If accessing locally, you may need to:"
|
|
||||||
echo " - Add '$hostname' to your hosts file"
|
if container_running; then
|
||||||
echo " - Or use: https://$(uci get network.lan.ipaddr 2>/dev/null || echo 'router-ip')/admin"
|
echo "=== Service Status ==="
|
||||||
|
docker exec "$CONTAINER_NAME" supervisorctl status 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_logs() {
|
||||||
|
docker logs "$@" "$CONTAINER_NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_shell() {
|
||||||
|
if container_running; then
|
||||||
|
docker exec -it "$CONTAINER_NAME" /bin/bash
|
||||||
|
else
|
||||||
|
log_error "Container not running"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_service_run() {
|
cmd_service_run() {
|
||||||
require_root || { echo Root required >&2; exit 1; }
|
require_root
|
||||||
check_prereqs || exit 1
|
check_prereqs || exit 1
|
||||||
defaults
|
load_config
|
||||||
stop_container
|
stop_container
|
||||||
|
|
||||||
local docker_args="--name $CONTAINER"
|
log_info "Starting mail server container..."
|
||||||
|
|
||||||
# Network mode: host for mail server functionality
|
# Build docker run command
|
||||||
docker_args="$docker_args --network host"
|
local docker_args="--name $CONTAINER_NAME"
|
||||||
|
|
||||||
# Volume mounts
|
# Hostname
|
||||||
docker_args="$docker_args -v $data_path/mail:/var/mail"
|
docker_args="$docker_args --hostname $hostname"
|
||||||
docker_args="$docker_args -v $data_path/ssl:/etc/ssl/mail"
|
docker_args="$docker_args --domainname $domain"
|
||||||
docker_args="$docker_args -v $data_path/data:/var/mail-state"
|
|
||||||
docker_args="$docker_args -v $data_path/dns:/etc/bind"
|
|
||||||
|
|
||||||
# Environment variables for docker-mailserver
|
# Ports
|
||||||
|
docker_args="$docker_args -p $smtp_port:25"
|
||||||
|
docker_args="$docker_args -p $submission_port:587"
|
||||||
|
docker_args="$docker_args -p $submissions_port:465"
|
||||||
|
docker_args="$docker_args -p $imap_port:143"
|
||||||
|
docker_args="$docker_args -p $imaps_port:993"
|
||||||
|
|
||||||
|
if [ "$enable_pop3" = "1" ]; then
|
||||||
|
docker_args="$docker_args -p $pop3_port:110"
|
||||||
|
docker_args="$docker_args -p $pop3s_port:995"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Volumes
|
||||||
|
docker_args="$docker_args -v $data_path/mail-data:/var/mail"
|
||||||
|
docker_args="$docker_args -v $data_path/mail-state:/var/mail-state"
|
||||||
|
docker_args="$docker_args -v $data_path/mail-logs:/var/log/mail"
|
||||||
|
docker_args="$docker_args -v $data_path/config:/tmp/docker-mailserver"
|
||||||
|
|
||||||
|
# Let's Encrypt volume if using certbot
|
||||||
|
if [ "$ssl_type" = "letsencrypt" ]; then
|
||||||
|
ensure_dir "$data_path/letsencrypt"
|
||||||
|
docker_args="$docker_args -v $data_path/letsencrypt:/etc/letsencrypt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
docker_args="$docker_args -e TZ=$timezone"
|
docker_args="$docker_args -e TZ=$timezone"
|
||||||
docker_args="$docker_args -e OVERRIDE_HOSTNAME=$hostname"
|
docker_args="$docker_args -e OVERRIDE_HOSTNAME=$hostname"
|
||||||
docker_args="$docker_args -e ENABLE_SPAMASSASSIN=1"
|
docker_args="$docker_args -e ENABLE_SPAMASSASSIN=$enable_spamassassin"
|
||||||
docker_args="$docker_args -e ENABLE_CLAMAV=1"
|
docker_args="$docker_args -e ENABLE_CLAMAV=$enable_clamav"
|
||||||
docker_args="$docker_args -e ENABLE_FAIL2BAN=1"
|
docker_args="$docker_args -e ENABLE_FAIL2BAN=$enable_fail2ban"
|
||||||
docker_args="$docker_args -e SSL_TYPE=letsencrypt"
|
docker_args="$docker_args -e ENABLE_POP3=$enable_pop3"
|
||||||
|
docker_args="$docker_args -e SSL_TYPE=$ssl_type"
|
||||||
|
docker_args="$docker_args -e PERMIT_DOCKER=network"
|
||||||
|
docker_args="$docker_args -e ONE_DIR=1"
|
||||||
|
docker_args="$docker_args -e POSTMASTER_ADDRESS=postmaster@$domain"
|
||||||
|
|
||||||
# Capabilities for mail server
|
if [ -n "$letsencrypt_email" ]; then
|
||||||
|
docker_args="$docker_args -e LETSENCRYPT_EMAIL=$letsencrypt_email"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Capabilities
|
||||||
docker_args="$docker_args --cap-add=NET_ADMIN"
|
docker_args="$docker_args --cap-add=NET_ADMIN"
|
||||||
docker_args="$docker_args --cap-add=NET_BIND_SERVICE"
|
docker_args="$docker_args --cap-add=SYS_PTRACE"
|
||||||
|
|
||||||
# Restart policy
|
# Restart policy
|
||||||
docker_args="$docker_args --restart=unless-stopped"
|
docker_args="$docker_args --restart=unless-stopped"
|
||||||
@ -209,19 +675,51 @@ cmd_service_run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd_service_stop() {
|
cmd_service_stop() {
|
||||||
require_root || { echo Root required >&2; exit 1; }
|
require_root
|
||||||
stop_container
|
stop_container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Main Entry Point
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
|
# Container management
|
||||||
install) shift; cmd_install "$@" ;;
|
install) shift; cmd_install "$@" ;;
|
||||||
check) shift; cmd_check "$@" ;;
|
check) shift; cmd_check "$@" ;;
|
||||||
update) shift; cmd_update "$@" ;;
|
update) shift; cmd_update "$@" ;;
|
||||||
status) shift; cmd_status "$@" ;;
|
status) shift; cmd_status "$@" ;;
|
||||||
logs) shift; cmd_logs "$@" ;;
|
logs) shift; cmd_logs "$@" ;;
|
||||||
admin) shift; cmd_admin "$@" ;;
|
shell) shift; cmd_shell "$@" ;;
|
||||||
service-run) shift; cmd_service_run "$@" ;;
|
service-run) shift; cmd_service_run "$@" ;;
|
||||||
service-stop) shift; cmd_service_stop "$@" ;;
|
service-stop) shift; cmd_service_stop "$@" ;;
|
||||||
|
|
||||||
|
# User management
|
||||||
|
user-add) shift; cmd_user_add "$@" ;;
|
||||||
|
user-del) shift; cmd_user_del "$@" ;;
|
||||||
|
user-list) shift; cmd_user_list "$@" ;;
|
||||||
|
user-passwd) shift; cmd_user_passwd "$@" ;;
|
||||||
|
alias-add) shift; cmd_alias_add "$@" ;;
|
||||||
|
alias-del) shift; cmd_alias_del "$@" ;;
|
||||||
|
alias-list) shift; cmd_alias_list "$@" ;;
|
||||||
|
|
||||||
|
# Domain & SSL
|
||||||
|
domain-add) shift; cmd_domain_add "$@" ;;
|
||||||
|
domain-list) shift; cmd_domain_list "$@" ;;
|
||||||
|
ssl-status) shift; cmd_ssl_status "$@" ;;
|
||||||
|
ssl-renew) shift; cmd_ssl_renew "$@" ;;
|
||||||
|
|
||||||
|
# Backup & restore
|
||||||
|
backup) shift; cmd_backup "$@" ;;
|
||||||
|
restore) shift; cmd_restore "$@" ;;
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
health) shift; cmd_health "$@" ;;
|
||||||
|
dns-check) shift; cmd_dns_check "$@" ;;
|
||||||
|
ports) shift; cmd_ports "$@" ;;
|
||||||
|
config) shift; cmd_config "$@" ;;
|
||||||
|
test-email) shift; cmd_test_email "$@" ;;
|
||||||
|
|
||||||
help|--help|-h|'') usage ;;
|
help|--help|-h|'') usage ;;
|
||||||
*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
|
*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user