stop for now

This commit is contained in:
Tommy Parnell
2025-08-04 04:16:00 -04:00
parent 596f25299b
commit 86fdc0b3ba
7 changed files with 1046 additions and 154 deletions

183
check-postfixadmin-paths.sh Executable file
View File

@@ -0,0 +1,183 @@
#!/bin/bash
# filepath: check-postfixadmin-paths.sh
# Check PostfixAdmin URL configuration and path handling
# This script verifies the correct URL structure for PostfixAdmin 3.3.11
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
}
echo -e "${BLUE}=== PostfixAdmin Path Configuration Analysis ===${NC}"
echo
info "Analyzing setup script configuration..."
WEBROOT="/var/www/postfixadmin"
NGINX_CONFIG="/etc/nginx/sites-available/postfixadmin.conf"
echo -e "${YELLOW}=== Directory Structure ===${NC}"
echo "Installation Directory: $WEBROOT"
echo "Public Directory: $WEBROOT/public"
echo "Setup Script: $WEBROOT/public/setup.php"
echo "Main Interface: $WEBROOT/public/index.php"
echo
echo -e "${YELLOW}=== URL Structure ===${NC}"
echo "With the current Nginx configuration pointing to $WEBROOT/public:"
echo
echo "✅ CORRECT URLs:"
echo " • PostfixAdmin Setup: https://yourhostname/setup.php"
echo " • PostfixAdmin Main: https://yourhostname/"
echo " • PostfixAdmin Login: https://yourhostname/login.php"
echo
echo "❌ INCORRECT URLs (would result in 404):"
echo " • https://yourhostname/postfixadmin/setup.php"
echo " • https://yourhostname/postfixadmin/"
echo
echo -e "${YELLOW}=== How the Setup Script Handles PostfixAdmin ===${NC}"
echo
echo "1. **Installation**:"
echo " - Downloads PostfixAdmin 3.3.11 to $WEBROOT"
echo " - Creates templates_c directory for Smarty templates"
echo " - Sets proper permissions (www-data:www-data)"
echo
echo "2. **Nginx Configuration**:"
echo " - Document root points to: $WEBROOT/public"
echo " - This is correct for PostfixAdmin 3.3.11+ structure"
echo " - PHP files are processed through PHP-FPM"
echo
echo "3. **PostfixAdmin Configuration (config.local.php)**:"
echo " - configured = false (allows setup wizard)"
echo " - Proper database credentials"
echo " - Encryption: dovecot:SHA512-CRYPT (compatible)"
echo " - Templates directory: $WEBROOT/templates_c"
echo
echo "4. **Setup Process**:"
echo " - User visits: https://hostname/setup.php"
echo " - Setup wizard creates database tables"
echo " - Admin user is created"
echo " - Configuration is finalized"
echo
echo -e "${YELLOW}=== PostfixAdmin 3.3.11 Directory Structure ===${NC}"
echo "PostfixAdmin 3.3.11 uses this structure:"
echo "$WEBROOT/"
echo "├── public/ # Web-accessible files"
echo "│ ├── index.php # Main interface"
echo "│ ├── setup.php # Setup wizard"
echo "│ ├── login.php # Login page"
echo "│ ├── css/ # Stylesheets"
echo "│ ├── js/ # JavaScript"
echo "│ └── images/ # Images"
echo "├── templates/ # Smarty templates"
echo "├── templates_c/ # Compiled templates (writable)"
echo "├── model/ # Application logic"
echo "├── languages/ # Translation files"
echo "└── config.local.php # Configuration file"
echo
echo -e "${YELLOW}=== Security Benefits ===${NC}"
echo "By pointing Nginx to the public/ directory:"
echo "✅ Configuration files are not web-accessible"
echo "✅ Template files are not web-accessible"
echo "✅ Application logic is not web-accessible"
echo "✅ Only intended public files can be accessed"
echo
# Check if files exist
echo -e "${YELLOW}=== Current Installation Check ===${NC}"
if [[ -d "$WEBROOT" ]]; then
success "PostfixAdmin directory exists: $WEBROOT"
if [[ -d "$WEBROOT/public" ]]; then
success "✅ Public directory exists: $WEBROOT/public"
if [[ -f "$WEBROOT/public/setup.php" ]]; then
success "✅ Setup script exists: $WEBROOT/public/setup.php"
else
warning "⚠️ Setup script not found: $WEBROOT/public/setup.php"
fi
if [[ -f "$WEBROOT/public/index.php" ]]; then
success "✅ Main interface exists: $WEBROOT/public/index.php"
else
warning "⚠️ Main interface not found: $WEBROOT/public/index.php"
fi
else
error "❌ Public directory missing: $WEBROOT/public"
echo " This indicates PostfixAdmin was not extracted correctly"
fi
if [[ -f "$WEBROOT/config.local.php" ]]; then
success "✅ Configuration file exists: $WEBROOT/config.local.php"
else
warning "⚠️ Configuration file not found: $WEBROOT/config.local.php"
fi
if [[ -d "$WEBROOT/templates_c" ]]; then
success "✅ Templates cache directory exists: $WEBROOT/templates_c"
if [[ -w "$WEBROOT/templates_c" ]]; then
success "✅ Templates cache directory is writable"
else
error "❌ Templates cache directory is not writable"
fi
else
warning "⚠️ Templates cache directory missing: $WEBROOT/templates_c"
fi
else
warning "PostfixAdmin not yet installed: $WEBROOT"
fi
# Check Nginx configuration
echo
if [[ -f "$NGINX_CONFIG" ]]; then
success "✅ Nginx configuration exists: $NGINX_CONFIG"
if grep -q "root.*public" "$NGINX_CONFIG"; then
success "✅ Nginx points to public directory"
else
warning "⚠️ Nginx may not be pointing to public directory"
fi
if [[ -L "/etc/nginx/sites-enabled/postfixadmin.conf" ]]; then
success "✅ Nginx site is enabled"
else
warning "⚠️ Nginx site is not enabled"
fi
else
warning "Nginx configuration not found: $NGINX_CONFIG"
fi
echo
echo -e "${BLUE}=== Summary ===${NC}"
echo "The setup script correctly handles PostfixAdmin paths by:"
echo "1. Installing to $WEBROOT"
echo "2. Configuring Nginx to serve from $WEBROOT/public"
echo "3. Making setup.php accessible at https://hostname/setup.php"
echo "4. Ensuring proper security by hiding non-public files"
echo
echo -e "${GREEN}Path configuration is correct for PostfixAdmin 3.3.11!${NC}"

179
finalize-postfixadmin-config.sh Executable file
View File

@@ -0,0 +1,179 @@
#!/bin/bash
# filepath: finalize-postfixadmin-config.sh
# Finalize PostfixAdmin configuration after setup wizard completion
# This script updates config.local.php to mark PostfixAdmin as configured
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
exit 1
fi
WEBROOT="/var/www/postfixadmin"
CONFIG_FILE="$WEBROOT/config.local.php"
# Check if config file exists
if [[ ! -f "$CONFIG_FILE" ]]; then
error "PostfixAdmin config file not found: $CONFIG_FILE"
exit 1
fi
info "Finalizing PostfixAdmin configuration..."
# Get current configuration values
read -p "Enter your domain name (e.g., example.com): " DOMAIN
read -p "Enter your hostname (e.g., mail.example.com): " HOSTNAME
read -p "Enter admin email address: " ADMIN_EMAIL
read -p "Enter database name [postfix]: " DB_NAME
DB_NAME=${DB_NAME:-postfix}
read -p "Enter database user [postfix]: " DB_USER
DB_USER=${DB_USER:-postfix}
read -s -p "Enter database password: " DB_PASSWORD
echo
read -s -p "Enter PostfixAdmin setup password: " POSTFIXADMIN_PASSWORD
echo
# Create the updated configuration
info "Creating finalized PostfixAdmin configuration..."
cat > "$CONFIG_FILE" << EOF
<?php
// PostfixAdmin Configuration
// This file contains the final configuration after setup wizard completion
\$CONF['configured'] = true; // Setup completed
// Database configuration
\$CONF['database_type'] = 'pgsql';
\$CONF['database_host'] = 'localhost';
\$CONF['database_user'] = '$DB_USER';
\$CONF['database_password'] = '$DB_PASSWORD';
\$CONF['database_name'] = '$DB_NAME';
// Setup password (hashed)
\$CONF['setup_password'] = '$(php -r "echo password_hash('$POSTFIXADMIN_PASSWORD', PASSWORD_DEFAULT);")';
// Site configuration
\$CONF['postfix_admin_url'] = 'https://$HOSTNAME';
\$CONF['postfix_admin_path'] = '$WEBROOT';
\$CONF['admin_email'] = '$ADMIN_EMAIL';
\$CONF['default_language'] = 'en';
// Mail configuration - use supported encryption method
\$CONF['encrypt'] = 'dovecot:SHA512-CRYPT';
\$CONF['dovecotpw'] = '/usr/bin/doveadm pw';
\$CONF['page_size'] = '10';
// Default aliases
\$CONF['default_aliases'] = array (
'abuse' => 'abuse@$DOMAIN',
'hostmaster' => 'hostmaster@$DOMAIN',
'postmaster' => 'postmaster@$DOMAIN',
'webmaster' => 'webmaster@$DOMAIN'
);
// Virtual domain configuration
\$CONF['domain_path'] = 'YES';
\$CONF['domain_in_mailbox'] = 'YES';
\$CONF['maildir_name_hook'] = 'maildir_name_hook';
// Template configuration
\$CONF['templates_c'] = '$WEBROOT/templates_c';
// Custom maildir naming function
function maildir_name_hook(\$domain, \$user) {
return \$domain . '/' . \$user . '/';
}
// Quota configuration
\$CONF['quota'] = 'YES';
\$CONF['quota_multiplier'] = 1024000;
// Security settings
\$CONF['min_password_length'] = 8;
\$CONF['generate_password'] = 'YES';
\$CONF['show_password'] = 'NO';
// Feature toggles
\$CONF['vacation'] = 'YES';
\$CONF['vacation_domain'] = 'autoreply.$DOMAIN';
\$CONF['aliases'] = '10';
\$CONF['mailboxes'] = '10';
\$CONF['maxquota'] = '10';
// Logging
\$CONF['logging'] = 'YES';
\$CONF['fetchmail'] = 'NO';
// Backup configuration
\$CONF['backup'] = 'YES';
// Theme and appearance
\$CONF['theme_logo'] = 'images/logo-default.png';
\$CONF['theme_css'] = 'default.css';
// Email settings
\$CONF['smtp_server'] = 'localhost';
\$CONF['smtp_port'] = '25';
// Footer text
\$CONF['footer_text'] = 'Return to $HOSTNAME';
\$CONF['footer_link'] = 'https://$HOSTNAME';
// Additional security
\$CONF['password_validation'] = array(
'/^.{8,}$/' => 'password_too_short 8',
'/[a-z]/' => 'password_no_characters',
'/[A-Z]/' => 'password_no_characters',
'/[0-9]/' => 'password_no_digits'
);
?>
EOF
# Set proper permissions
chown www-data:www-data "$CONFIG_FILE"
chmod 640 "$CONFIG_FILE"
success "PostfixAdmin configuration finalized!"
echo
echo -e "${BLUE}=== Configuration Summary ===${NC}"
echo "Config file: $CONFIG_FILE"
echo "Configured: true"
echo "Database: $DB_NAME on localhost"
echo "Domain: $DOMAIN"
echo "Hostname: $HOSTNAME"
echo "Admin email: $ADMIN_EMAIL"
echo
echo -e "${YELLOW}=== Next Steps ===${NC}"
echo "1. Access PostfixAdmin: https://$HOSTNAME/"
echo "2. Log in with your admin credentials"
echo "3. Start creating domains and mailboxes"
echo
echo -e "${GREEN}PostfixAdmin is now ready for use!${NC}"

103
fix-clamv.sh Normal file
View File

@@ -0,0 +1,103 @@
#!/bin/bash
# filepath: fix-clamav.sh
# Fix ClamAV freshclam lock issue
# Run this script if you encounter ClamAV signature update errors
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
exit 1
fi
info "Fixing ClamAV freshclam lock issue..."
# Stop ClamAV services
info "Stopping ClamAV services..."
systemctl stop clamav-daemon 2>/dev/null || true
systemctl stop clamav-freshclam 2>/dev/null || true
# Wait for services to stop
sleep 3
# Remove any stale lock files
info "Removing stale lock files..."
rm -f /var/log/clamav/freshclam.log.lock
rm -f /var/run/clamav/freshclam.pid
# Check log file permissions
info "Checking log file permissions..."
touch /var/log/clamav/freshclam.log
chown clamav:clamav /var/log/clamav/freshclam.log
chmod 644 /var/log/clamav/freshclam.log
# Update signatures manually
info "Updating ClamAV signatures..."
if sudo -u clamav freshclam --quiet; then
success "ClamAV signatures updated successfully"
else
warning "Manual signature update failed, but services will handle this automatically"
fi
# Restart services
info "Restarting ClamAV services..."
systemctl start clamav-freshclam
sleep 2
systemctl start clamav-daemon
# Check service status
if systemctl is-active --quiet clamav-freshclam; then
success "clamav-freshclam service is running"
else
warning "clamav-freshclam service failed to start"
fi
if systemctl is-active --quiet clamav-daemon; then
success "clamav-daemon service is running"
else
warning "clamav-daemon service failed to start"
fi
# Restart amavis to ensure it can connect to ClamAV
info "Restarting amavis service..."
systemctl restart amavis
if systemctl is-active --quiet amavis; then
success "amavis service is running"
else
warning "amavis service failed to restart"
fi
success "ClamAV fix completed!"
echo
echo -e "${BLUE}Service Status:${NC}"
systemctl status clamav-freshclam --no-pager -l || true
echo
systemctl status clamav-daemon --no-pager -l || true
echo
systemctl status amavis --no-pager -l || true

View File

@@ -0,0 +1,114 @@
#!/bin/bash
# Fix PostfixAdmin Password Hashing Configuration
# This script fixes the dovecot password hashing error in PostfixAdmin
# Author: Email Server Setup Script
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
WEBROOT="/var/www/postfixadmin"
CONFIG_FILE="$WEBROOT/config.local.php"
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
# Check if config file exists
if [[ ! -f "$CONFIG_FILE" ]]; then
error "PostfixAdmin config file not found: $CONFIG_FILE"
fi
echo -e "${BLUE}PostfixAdmin Password Hashing Fix${NC}"
echo "=================================="
echo
echo "This script fixes the dovecot password hashing error by switching"
echo "from 'dovecot:SHA512-CRYPT' to 'php_crypt:SHA512' which doesn't"
echo "require external dovecot commands."
echo
# Create backup
backup_file="$CONFIG_FILE.backup.$(date +%Y%m%d_%H%M%S)"
cp "$CONFIG_FILE" "$backup_file"
info "Created backup: $backup_file"
# Check if the problematic configuration exists
if grep -q "dovecot:SHA512-CRYPT" "$CONFIG_FILE"; then
info "Found problematic dovecot configuration, fixing..."
# Replace the encrypt method
sed -i "s/\$CONF\['encrypt'\] = 'dovecot:SHA512-CRYPT';/\$CONF['encrypt'] = 'php_crypt:SHA512';/" "$CONFIG_FILE"
# Remove or comment out the dovecotpw line if it exists
sed -i "/\$CONF\['dovecotpw'\]/d" "$CONFIG_FILE"
success "Updated password encryption method to php_crypt:SHA512"
elif grep -q "php_crypt:SHA512" "$CONFIG_FILE"; then
success "Configuration already uses php_crypt:SHA512 - no changes needed"
else
warning "Could not find encryption configuration in config file"
info "Adding php_crypt:SHA512 configuration..."
# Add the encryption method before the closing PHP tag
sed -i '/^?>/i \$CONF['\''encrypt'\''] = '\''php_crypt:SHA512'\'';' "$CONFIG_FILE"
success "Added php_crypt:SHA512 configuration"
fi
# Verify the change
if grep -q "php_crypt:SHA512" "$CONFIG_FILE"; then
success "Configuration verified: using php_crypt:SHA512"
else
error "Verification failed - configuration may not have been updated correctly"
fi
# Set appropriate permissions
chown www-data:www-data "$CONFIG_FILE"
chmod 644 "$CONFIG_FILE"
echo
echo -e "${GREEN}PostfixAdmin password hashing fixed!${NC}"
echo
echo -e "${BLUE}What this script did:${NC}"
echo "• Changed encryption from 'dovecot:SHA512-CRYPT' to 'php_crypt:SHA512'"
echo "• Removed dovecotpw command dependency"
echo "• Created a backup of your original config"
echo "• Set appropriate file permissions"
echo
echo -e "${BLUE}What this means:${NC}"
echo "• PostfixAdmin will use PHP's built-in crypt() function"
echo "• No dependency on external dovecot commands"
echo "• Passwords will still be SHA512-CRYPT compatible with Dovecot"
echo "• The setup wizard should now work properly"
echo
echo -e "${YELLOW}Next steps:${NC}"
echo "• Refresh your PostfixAdmin setup page"
echo "• The password hashing error should be resolved"
echo "• Continue with the setup wizard"
echo
echo -e "${YELLOW}Note: If you need to revert these changes,${NC}"
echo -e "${YELLOW}restore the backup file: $backup_file${NC}"

View File

@@ -28,7 +28,7 @@ WEBROOT="/var/www/postfixadmin"
POSTFIXADMIN_VERSION="postfixadmin-3.3.11.tar.gz"
# New: Define the mail volume path
MAIL_VOLUME_PATH="/mnt/MainEmail"
MAIL_VOLUME_PATH="/mnt/email"
# Logging
LOG_FILE="/var/log/email-server-setup.log"
@@ -178,112 +178,33 @@ configure_postgresql() {
systemctl start postgresql
systemctl enable postgresql
# Create database and user
# Create database and user with full permissions for PostfixAdmin setup
sudo -u postgres psql -c "CREATE DATABASE $DB_NAME;" || warning "Database already exists, skipping."
sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';" || warning "User already exists, skipping."
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;"
# Grant comprehensive permissions needed for PostfixAdmin setup wizard
sudo -u postgres psql -d "$DB_NAME" << EOF
-- Grant all privileges on database
GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;
# Create tables for Postfix
sudo -u postgres psql -d "$DB_NAME" << 'EOF'
CREATE TABLE IF NOT EXISTS domains (
domain varchar(50) NOT NULL,
description varchar(255),
aliases int NOT NULL default '0',
mailboxes int NOT NULL default '0',
maxquota bigint NOT NULL default '0',
quota bigint NOT NULL default '0',
transport varchar(255) default NULL,
backupmx boolean NOT NULL default '0',
created timestamp NOT NULL default now(),
modified timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (domain)
);
-- Grant schema permissions
GRANT ALL PRIVILEGES ON SCHEMA public TO $DB_USER;
GRANT CREATE ON SCHEMA public TO $DB_USER;
CREATE TABLE IF NOT EXISTS aliases (
address varchar(255) NOT NULL,
goto text NOT NULL,
domain varchar(255) NOT NULL,
created timestamp NOT NULL default now(),
modified timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (address)
);
-- Allow user to create tables, sequences, etc.
ALTER USER $DB_USER CREATEDB;
CREATE TABLE IF NOT EXISTS mailbox (
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
name varchar(255) NOT NULL default '',
maildir varchar(255) NOT NULL default '',
quota bigint NOT NULL default '0',
local_part varchar(255) NOT NULL,
domain varchar(255) NOT NULL,
created timestamp NOT NULL default now(),
modified timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (username)
);
-- Set user as owner of public schema to allow full table management
ALTER SCHEMA public OWNER TO $DB_USER;
CREATE TABLE IF NOT EXISTS domain_admins (
username varchar(255) NOT NULL,
domain varchar(255) NOT NULL,
created timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (username, domain)
);
CREATE TABLE IF NOT EXISTS admin (
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
created timestamp NOT NULL default now(),
modified timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (username)
);
CREATE TABLE IF NOT EXISTS log (
timestamp timestamp NOT NULL default now(),
username varchar(255) NOT NULL default '',
domain varchar(255) NOT NULL default '',
action varchar(255) NOT NULL default '',
data text NOT NULL default ''
);
CREATE TABLE IF NOT EXISTS vacation (
email varchar(255) NOT NULL,
subject varchar(255) NOT NULL,
body text NOT NULL,
cache text NOT NULL default '',
domain varchar(255) NOT NULL,
created timestamp NOT NULL default now(),
active boolean NOT NULL default '1',
PRIMARY KEY (email)
);
CREATE TABLE IF NOT EXISTS quota (
username varchar(255) NOT NULL,
path varchar(100) NOT NULL,
current bigint NOT NULL default 0,
PRIMARY KEY (username, path)
);
CREATE TABLE IF NOT EXISTS quota2 (
username varchar(100) NOT NULL,
bytes bigint NOT NULL default 0,
messages int NOT NULL default 0,
PRIMARY KEY (username)
);
-- Grant default privileges for future objects
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO $DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO $DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO $DB_USER;
EOF
# Grant permissions
sudo -u postgres psql -d "$DB_NAME" -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO $DB_USER;"
sudo -u postgres psql -d "$DB_NAME" -c "GRANT INSERT, UPDATE, DELETE ON aliases, mailbox, domain_admins, domains TO $DB_USER;"
sudo -u postgres psql -d "$DB_NAME" -c "GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO $DB_USER;"
# Insert the primary domain
sudo -u postgres psql -d "$DB_NAME" -c "INSERT INTO domains (domain, description, active) VALUES ('$DOMAIN', 'Primary domain configured during setup', '1') ON CONFLICT (domain) DO NOTHING;"
success "PostgreSQL configured"
success "PostgreSQL configured for PostfixAdmin setup wizard"
info "Database tables will be created by PostfixAdmin setup wizard"
}
# ---
@@ -291,6 +212,9 @@ EOF
# Nginx is now configured with a basic HTTP virtual host first, allowing Certbot to run successfully.
# ---
# Install PostfixAdmin and configure Nginx for HTTP
# Replace the install_postfixadmin() function with this updated version:
# Install PostfixAdmin and configure Nginx for HTTP
install_postfixadmin() {
info "Installing PostfixAdmin..."
@@ -301,17 +225,25 @@ install_postfixadmin() {
tar -xzf $POSTFIXADMIN_VERSION
mv postfixadmin-postfixadmin-3.3.11 $WEBROOT
# Create necessary directories
mkdir -p $WEBROOT/templates_c
mkdir -p $WEBROOT/logs
# Set permissions
chown -R www-data:www-data $WEBROOT
find $WEBROOT -type d -exec chmod 755 {} \;
find $WEBROOT -type f -exec chmod 644 {} \;
# Ensure templates_c is writable
chmod 755 $WEBROOT/templates_c
chown www-data:www-data $WEBROOT/templates_c
# Create PostfixAdmin configuration
cat > $WEBROOT/config.local.php << EOF
<?php
\$CONF['configured'] = true;
\$CONF['configured'] = false; // Allow setup wizard to run
\$CONF['setup_password'] = '$(php -r "echo password_hash('$POSTFIXADMIN_PASSWORD', PASSWORD_DEFAULT);")';
\$CONF['postfix_admin_url'] = 'https://$HOSTNAME/postfixadmin';
\$CONF['postfix_admin_url'] = 'https://$HOSTNAME';
\$CONF['postfix_admin_path'] = '$WEBROOT';
\$CONF['default_language'] = 'en';
\$CONF['database_type'] = 'pgsql';
@@ -320,8 +252,9 @@ install_postfixadmin() {
\$CONF['database_password'] = '$DB_PASSWORD';
\$CONF['database_name'] = '$DB_NAME';
\$CONF['admin_email'] = '$ADMIN_EMAIL';
\$CONF['encrypt'] = 'sha512.crypt';
\$CONF['dovecotpw'] = "/usr/bin/doveadm pw";
// Use PHP-based encryption instead of dovecot command for compatibility
\$CONF['encrypt'] = 'php_crypt:SHA512';
\$CONF['page_size'] = '10';
\$CONF['default_aliases'] = array (
'abuse' => 'abuse@change-this-to-your.domain.tld',
@@ -332,13 +265,14 @@ install_postfixadmin() {
\$CONF['domain_path'] = 'YES';
\$CONF['domain_in_mailbox'] = 'YES';
\$CONF['maildir_name_hook'] = 'maildir_name_hook';
\$CONF['templates_c'] = '$WEBROOT/templates_c';
function maildir_name_hook(\$domain, \$user) {
return \$domain . '/' . \$user . '/';
}
?>
EOF
# Configure Nginx virtual host with a basic HTTP block
# Configure Nginx virtual host with proper public directory
cat > /etc/nginx/sites-available/postfixadmin.conf << EOF
server {
listen 80;
@@ -346,6 +280,10 @@ server {
root $WEBROOT/public;
index index.php index.html index.htm;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
location / {
try_files \$uri \$uri/ /index.php?\$args;
}
@@ -355,17 +293,51 @@ server {
fastcgi_pass unix:/var/run/php/php$(php -r "echo PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;")-fpm.sock;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
fastcgi_read_timeout 600s;
fastcgi_param PATH_INFO \$fastcgi_path_info;
include fastcgi_params;
}
# Deny access to sensitive files and directories
location ~ /\. {
deny all;
}
# Deny access to config and other sensitive directories outside public
location ~ ^/(config|logs|templates_c|scripts|DOCUMENTS|INSTALL|upgrade)/ {
deny all;
}
# Allow access to public assets
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# Enable Nginx site and disable default
ln -s /etc/nginx/sites-available/postfixadmin.conf /etc/nginx/sites-enabled/
ln -sf /etc/nginx/sites-available/postfixadmin.conf /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
success "PostfixAdmin installed and Nginx configured for HTTP"
}
# Test write permissions
if sudo -u www-data touch $WEBROOT/templates_c/test_write 2>/dev/null; then
rm -f $WEBROOT/templates_c/test_write
success "PostfixAdmin write permissions verified"
else
error "PostfixAdmin templates_c directory is not writable by www-data"
fi
# Verify public directory exists
if [[ -d "$WEBROOT/public" ]]; then
success "PostfixAdmin public directory found"
else
warning "PostfixAdmin public directory not found - this may cause 404 errors"
info "Directory contents of $WEBROOT:"
ls -la "$WEBROOT" || true
fi
success "PostfixAdmin installed and Nginx configured for HTTP with public directory"
}
# Get Let's Encrypt certificates
get_ssl_certificates() {
info "Obtaining Let's Encrypt certificates..."
@@ -668,8 +640,20 @@ EOF
configure_amavis() {
info "Configuring Amavis and SpamAssassin..."
# Stop freshclam service temporarily to avoid lock conflicts
systemctl stop clamav-freshclam 2>/dev/null || true
# Wait a moment for the service to fully stop
sleep 2
# Update ClamAV signatures
freshclam
info "Updating ClamAV virus signatures..."
if ! freshclam --quiet; then
warning "Failed to update ClamAV signatures manually. The automatic updater will handle this."
fi
# Restart freshclam service
systemctl start clamav-freshclam 2>/dev/null || true
# Configure Amavis
cat > /etc/amavis/conf.d/15-content_filter_mode << 'EOF'
@@ -746,39 +730,6 @@ EOF
success "Amavis and SpamAssassin configured"
}
# Configure firewall
configure_firewall() {
info "Configuring firewall..."
# Reset UFW
ufw --force reset
# Default policies
ufw default deny incoming
ufw default allow outgoing
# Allow SSH
ufw allow ssh
# Allow email ports
ufw allow 25/tcp # SMTP
ufw allow 587/tcp # Submission
ufw allow 465/tcp # SMTPS
ufw allow 110/tcp # POP3
ufw allow 995/tcp # POP3S
ufw allow 143/tcp # IMAP
ufw allow 993/tcp # IMAPS
# Allow web ports
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
# Enable UFW
ufw --force enable
success "Firewall configured"
}
# Start and enable services
start_services() {
info "Starting and enabling services..."
@@ -786,18 +737,65 @@ start_services() {
# Reload systemd
systemctl daemon-reload
# Start and enable services
# Start and enable core services first
systemctl enable --now postgresql
systemctl enable --now postfix
systemctl enable --now dovecot
systemctl enable --now amavis
systemctl enable --now spamassassin
systemctl enable --now clamav-daemon
systemctl enable --now clamav-freshclam
systemctl enable --now opendkim
systemctl enable --now nginx
systemctl enable --now php$(php -r "echo PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;")-fpm
# Start ClamAV services with better error handling
info "Starting ClamAV services..."
# Start clamav-freshclam first (for signature updates)
if systemctl list-unit-files --full | grep -q "clamav-freshclam.service"; then
systemctl enable clamav-freshclam
systemctl start clamav-freshclam
# Wait for freshclam to complete initial signature update
info "Waiting for ClamAV signature update to complete..."
for i in {1..30}; do
if systemctl is-active --quiet clamav-freshclam &&
[[ -f /var/lib/clamav/main.cvd || -f /var/lib/clamav/main.cld ]]; then
break
fi
sleep 2
done
else
warning "ClamAV freshclam service file not found. Skipping."
fi
# Now start clamav-daemon
if systemctl list-unit-files --full | grep -q "clamav-daemon.service"; then
systemctl enable clamav-daemon
systemctl start clamav-daemon
# Wait for daemon to start
sleep 3
if systemctl is-active --quiet clamav-daemon; then
success "ClamAV daemon started successfully"
else
warning "ClamAV daemon failed to start. Check logs with: journalctl -u clamav-daemon"
fi
else
warning "ClamAV daemon service file not found (expected 'clamav-daemon.service'). Skipping."
fi
# Start mail services
systemctl enable --now postfix
systemctl enable --now dovecot
systemctl enable --now opendkim
# Start Amavis (depends on ClamAV)
systemctl enable --now amavis
# Enable SpamAssassin service (handle potential name differences)
if systemctl list-unit-files --full | grep -q "spamassassin.service"; then
systemctl enable --now spamassassin
elif systemctl list-unit-files --full | grep -q "spamd.service"; then
systemctl enable --now spamd
else
warning "SpamAssassin service file not found (expected 'spamassassin.service' or 'spamd.service'). Skipping."
fi
success "All services started and enabled"
}
@@ -810,7 +808,7 @@ display_final_info() {
echo "Hostname: $HOSTNAME"
echo "Admin Email: $ADMIN_EMAIL"
echo "Mailbox Location: $MAIL_VOLUME_PATH/vhosts"
echo "PostfixAdmin URL: https://$HOSTNAME/postfixadmin/"
echo "PostfixAdmin URL: https://$HOSTNAME/"
echo
echo -e "${YELLOW}=== DNS Records to Add for $DOMAIN ===${NC}"
echo "A $HOSTNAME [Your server IP]"
@@ -823,9 +821,12 @@ display_final_info() {
echo
echo -e "${YELLOW}=== Next Steps ===${NC}"
echo "1. Add the DNS records shown above"
echo "2. Visit https://$HOSTNAME/postfixadmin/setup.php to complete PostfixAdmin setup"
echo "3. Create your first domain and mailbox in PostfixAdmin"
echo "4. Test email sending and receiving"
echo "2. Visit https://$HOSTNAME/setup.php to complete PostfixAdmin setup"
echo "3. After completing the setup wizard, run ONE of these scripts:"
echo " • ./toggle-postfixadmin-configured.sh (quick toggle configured = true)"
echo " • ./finalize-postfixadmin-config.sh (complete reconfiguration)"
echo "4. Create your first domain and mailbox in PostfixAdmin"
echo "5. Test email sending and receiving"
echo
echo -e "${BLUE}=== Multiple Domain Support ===${NC}"
echo "This server supports unlimited virtual domains!"
@@ -871,7 +872,7 @@ main() {
configure_dovecot
configure_opendkim
configure_amavis
configure_firewall
# configure_firewall
display_final_info
}

102
toggle-postfixadmin-configured.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
# Quick PostfixAdmin Configuration Toggle
# This script simply sets configured = true after setup wizard completion
# Use this if you've already completed the setup wizard via web interface
# Author: Email Server Setup Script
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
WEBROOT="/var/www/postfixadmin"
CONFIG_FILE="$WEBROOT/config.local.php"
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
# Check if config file exists
if [[ ! -f "$CONFIG_FILE" ]]; then
error "PostfixAdmin config file not found: $CONFIG_FILE"
fi
echo -e "${BLUE}PostfixAdmin Configuration Toggle${NC}"
echo "=================================="
echo
# Check current status
if grep -q "\$CONF\['configured'\] = true;" "$CONFIG_FILE"; then
warning "PostfixAdmin is already marked as configured"
echo "If you need to run the setup wizard again, you can change it back to false."
exit 0
fi
if grep -q "\$CONF\['configured'\] = false;" "$CONFIG_FILE"; then
info "Found configured = false in config file"
else
error "Could not find configured setting in config file"
fi
echo "This script will change PostfixAdmin from configured = false to configured = true"
echo "This should be done AFTER you have completed the setup wizard at /setup.php"
echo
read -p "Have you completed the PostfixAdmin setup wizard? (y/N): " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
info "Please complete the setup wizard first at https://your-hostname/setup.php"
exit 0
fi
# Create backup
backup_file="$CONFIG_FILE.backup.$(date +%Y%m%d_%H%M%S)"
cp "$CONFIG_FILE" "$backup_file"
info "Created backup: $backup_file"
# Update the configuration
if sed -i "s/\$CONF\['configured'\] = false;/\$CONF['configured'] = true;/" "$CONFIG_FILE"; then
success "Updated: configured = false → configured = true"
else
error "Failed to update configuration"
fi
# Verify the change
if grep -q "\$CONF\['configured'\] = true;" "$CONFIG_FILE"; then
success "Configuration verified: PostfixAdmin is now marked as configured"
else
error "Verification failed - configuration may not have been updated correctly"
fi
echo
echo -e "${GREEN}PostfixAdmin setup completed!${NC}"
echo
echo -e "${BLUE}What this means:${NC}"
echo "• The setup wizard (/setup.php) is now disabled for security"
echo "• PostfixAdmin is ready for normal use"
echo "• You can now create domains and mailboxes"
echo
echo -e "${YELLOW}Note: If you need to run the setup wizard again,${NC}"
echo -e "${YELLOW}restore the backup file or manually change configured back to false${NC}"

210
verify-postfixadmin-config.sh Executable file
View File

@@ -0,0 +1,210 @@
#!/bin/bash
# filepath: verify-postfixadmin-config.sh
# Verify PostfixAdmin configuration and supported encryption methods
# This script checks the current configuration and provides recommendations
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
info() {
echo -e "${BLUE}INFO: $1${NC}"
}
success() {
echo -e "${GREEN}SUCCESS: $1${NC}"
}
warning() {
echo -e "${YELLOW}WARNING: $1${NC}"
}
error() {
echo -e "${RED}ERROR: $1${NC}" >&2
}
WEBROOT="/var/www/postfixadmin"
CONFIG_FILE="$WEBROOT/config.local.php"
echo -e "${BLUE}=== PostfixAdmin Configuration Verification ===${NC}"
echo
# Check if PostfixAdmin is installed
if [[ -d "$WEBROOT" ]]; then
success "PostfixAdmin directory found: $WEBROOT"
else
error "PostfixAdmin directory not found: $WEBROOT"
exit 1
fi
# Check config file
if [[ -f "$CONFIG_FILE" ]]; then
success "Configuration file found: $CONFIG_FILE"
else
warning "Configuration file not found: $CONFIG_FILE"
echo "Run the setup script first to create the configuration."
exit 1
fi
# Check encryption method
echo
info "Checking encryption configuration..."
if grep -q "dovecot:SHA512-CRYPT" "$CONFIG_FILE"; then
success "✅ Using supported encryption: dovecot:SHA512-CRYPT"
elif grep -q "sha512.crypt" "$CONFIG_FILE"; then
error "❌ Using unsupported encryption: sha512.crypt"
echo " Fix: Change to 'dovecot:SHA512-CRYPT'"
elif grep -q "encrypt" "$CONFIG_FILE"; then
ENCRYPT_METHOD=$(grep "encrypt" "$CONFIG_FILE" | head -1 | cut -d"'" -f4)
warning "⚠️ Using encryption method: $ENCRYPT_METHOD"
echo " Recommended: 'dovecot:SHA512-CRYPT'"
else
warning "No encryption method found in configuration"
fi
# Check if configured
echo
info "Checking configuration status..."
if grep -q "configured.*true" "$CONFIG_FILE"; then
success "✅ PostfixAdmin is marked as configured"
elif grep -q "configured.*false" "$CONFIG_FILE"; then
info "⏳ PostfixAdmin is not yet configured (setup wizard available)"
else
warning "Configuration status unclear"
fi
# Check database configuration
echo
info "Checking database configuration..."
if grep -q "database_type.*pgsql" "$CONFIG_FILE"; then
success "✅ Using PostgreSQL database"
else
warning "Database type not found or not PostgreSQL"
fi
if grep -q "database_host.*localhost" "$CONFIG_FILE"; then
success "✅ Database host: localhost"
fi
# Check dovecotpw path
echo
info "Checking Dovecot integration..."
if grep -q "dovecotpw.*doveadm" "$CONFIG_FILE"; then
success "✅ Using doveadm for password operations"
# Test if doveadm is available
if command -v doveadm >/dev/null 2>&1; then
success "✅ doveadm command is available"
# Test encryption
if echo "test" | doveadm pw -s SHA512-CRYPT >/dev/null 2>&1; then
success "✅ SHA512-CRYPT encryption is supported"
else
warning "⚠️ SHA512-CRYPT test inconclusive"
fi
else
error "❌ doveadm command not found"
echo " Install Dovecot: apt-get install dovecot-core"
fi
else
warning "Dovecot integration not configured"
fi
# Check public directory
echo
info "Checking web server configuration..."
if [[ -d "$WEBROOT/public" ]]; then
success "✅ PostfixAdmin public directory exists"
else
error "❌ PostfixAdmin public directory missing"
echo " Expected: $WEBROOT/public"
echo " Check PostfixAdmin version and extraction"
fi
# Check permissions
echo
info "Checking file permissions..."
if [[ -w "$WEBROOT/templates_c" ]]; then
success "✅ templates_c directory is writable"
else
error "❌ templates_c directory is not writable"
echo " Fix: chown -R www-data:www-data $WEBROOT/templates_c"
fi
# Check Nginx configuration
echo
info "Checking web server configuration..."
if [[ -f "/etc/nginx/sites-enabled/postfixadmin.conf" ]]; then
success "✅ Nginx PostfixAdmin site is enabled"
if grep -q "root.*public" "/etc/nginx/sites-enabled/postfixadmin.conf"; then
success "✅ Nginx points to public directory"
else
warning "⚠️ Nginx may not be pointing to public directory"
fi
else
warning "Nginx PostfixAdmin configuration not found"
fi
# Check Postfix integration
echo
info "Checking Postfix integration..."
POSTFIX_CONFIGS=(
"/etc/postfix/pgsql-virtual-mailbox-domains.cf"
"/etc/postfix/pgsql-virtual-mailbox-maps.cf"
"/etc/postfix/pgsql-virtual-alias-maps.cf"
)
for config in "${POSTFIX_CONFIGS[@]}"; do
if [[ -f "$config" ]]; then
success "✅ Found: $(basename "$config")"
else
error "❌ Missing: $(basename "$config")"
fi
done
# Summary
echo
echo -e "${BLUE}=== Configuration Summary ===${NC}"
echo
echo -e "${YELLOW}Supported PostfixAdmin 3.3.11 Encryption Methods:${NC}"
echo "✅ dovecot:SHA512-CRYPT (recommended)"
echo "✅ dovecot:SHA256-CRYPT"
echo "✅ dovecot:BLF-CRYPT"
echo "✅ md5crypt"
echo "✅ sha512"
echo "❌ sha512.crypt (unsupported)"
echo "❌ cleartext (not recommended)"
echo
echo -e "${YELLOW}PostfixAdmin Database Tables:${NC}"
echo "Required tables created by setup wizard:"
echo "• admin"
echo "• alias"
echo "• config"
echo "• domain"
echo "• domain_admins"
echo "• fetchmail"
echo "• log"
echo "• mailbox"
echo "• quota"
echo "• quota2"
echo "• vacation"
echo "• vacation_notification"
echo
echo -e "${YELLOW}Access URLs:${NC}"
if grep -q "postfix_admin_url" "$CONFIG_FILE"; then
ADMIN_URL=$(grep "postfix_admin_url" "$CONFIG_FILE" | cut -d"'" -f4)
echo "PostfixAdmin: $ADMIN_URL/"
echo "Setup wizard: $ADMIN_URL/setup.php"
else
echo "PostfixAdmin: https://your-hostname/"
echo "Setup wizard: https://your-hostname/setup.php"
fi
echo
echo -e "${GREEN}Configuration verification completed!${NC}"