From b1c0fcf1f1e184f6e74f95eb7a3a2dd397534c23 Mon Sep 17 00:00:00 2001 From: Tommy Parnell Date: Sun, 3 Aug 2025 16:31:47 -0400 Subject: [PATCH] ok fix --- setup-email-server.sh | 372 ++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 216 deletions(-) diff --git a/setup-email-server.sh b/setup-email-server.sh index 322fb8c..d0b7108 100755 --- a/setup-email-server.sh +++ b/setup-email-server.sh @@ -69,29 +69,29 @@ check_root() { get_configuration() { echo -e "${BLUE}Email Server Configuration${NC}" echo "=================================" - + while [[ -z "$DOMAIN" ]]; do read -p "Enter your domain name (e.g., example.com): " DOMAIN done - + while [[ -z "$HOSTNAME" ]]; do read -p "Enter your hostname (e.g., mail.example.com): " HOSTNAME done - + while [[ -z "$ADMIN_EMAIL" ]]; do read -p "Enter admin email address: " ADMIN_EMAIL done - + while [[ -z "$DB_PASSWORD" ]]; do read -s -p "Enter PostgreSQL password for postfix user: " DB_PASSWORD echo done - + while [[ -z "$POSTFIXADMIN_PASSWORD" ]]; do read -s -p "Enter PostfixAdmin setup password: " POSTFIXADMIN_PASSWORD echo done - + info "Configuration completed" } @@ -105,7 +105,7 @@ update_system() { # Install required packages install_packages() { info "Installing required packages..." - + # Install basic packages apt install -y \ curl \ @@ -117,10 +117,10 @@ install_packages() { python3-certbot-nginx \ nginx \ ufw - + # Install PostgreSQL apt install -y postgresql postgresql-contrib - + # Install Postfix and related packages debconf-set-selections <<< "postfix postfix/mailname string $HOSTNAME" debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'" @@ -128,7 +128,7 @@ install_packages() { postfix \ postfix-pgsql \ postfix-policyd-spf-python - + # Install Dovecot apt install -y \ dovecot-core \ @@ -136,7 +136,7 @@ install_packages() { dovecot-pop3d \ dovecot-lmtpd \ dovecot-pgsql - + # Install Amavis and SpamAssassin apt install -y \ amavisd-new \ @@ -144,7 +144,7 @@ install_packages() { clamav \ clamav-daemon \ clamav-freshclam - + # Try to install clamav-unofficial-sigs if available if apt-cache show clamav-unofficial-sigs >/dev/null 2>&1; then apt install -y clamav-unofficial-sigs @@ -152,10 +152,10 @@ install_packages() { else warning "clamav-unofficial-sigs package not available, skipping (this is normal on newer systems)" fi - + # Install OpenDKIM apt install -y opendkim opendkim-tools - + # Install PHP and extensions for PostfixAdmin apt install -y \ php-fpm \ @@ -166,23 +166,23 @@ install_packages() { php-curl \ php-zip \ php-gd - + success "All packages installed" } # Configure PostgreSQL configure_postgresql() { info "Configuring PostgreSQL..." - + # Start PostgreSQL systemctl start postgresql systemctl enable postgresql - + # Create database and user 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;" - + # Create tables for Postfix sudo -u postgres psql -d "$DB_NAME" << 'EOF' CREATE TABLE IF NOT EXISTS domains ( @@ -274,25 +274,124 @@ CREATE TABLE IF NOT EXISTS quota2 ( PRIMARY KEY (username) ); 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" } +# --- +# NOTE: The order of web server setup has been corrected here. +# Nginx is now configured with a basic HTTP virtual host first, allowing Certbot to run successfully. +# --- + +# Install PostfixAdmin and configure Nginx for HTTP +install_postfixadmin() { + info "Installing PostfixAdmin..." + + # Download PostfixAdmin + cd /tmp + wget -q https://github.com/postfixadmin/postfixadmin/archive/$POSTFIXADMIN_VERSION || error "Failed to download PostfixAdmin" + tar -xzf $POSTFIXADMIN_VERSION + mv postfixadmin-postfixadmin-3.3.11 $WEBROOT + + # Set permissions + chown -R www-data:www-data $WEBROOT + find $WEBROOT -type d -exec chmod 755 {} \; + find $WEBROOT -type f -exec chmod 644 {} \; + + # Create PostfixAdmin configuration + cat > $WEBROOT/config.local.php << EOF + 'abuse@change-this-to-your.domain.tld', + 'hostmaster' => 'hostmaster@change-this-to-your.domain.tld', + 'postmaster' => 'postmaster@change-this-to-your.domain.tld', + 'webmaster' => 'webmaster@change-this-to-your.domain.tld' +); +\$CONF['domain_path'] = 'YES'; +\$CONF['domain_in_mailbox'] = 'YES'; +\$CONF['maildir_name_hook'] = 'maildir_name_hook'; +function maildir_name_hook(\$domain, \$user) { + return \$domain . '/' . \$user . '/'; +} +?> +EOF + + # Configure Nginx virtual host with a basic HTTP block + cat > /etc/nginx/sites-available/postfixadmin.conf << EOF +server { + listen 80; + server_name $HOSTNAME; + root $WEBROOT/public; + index index.php index.html index.htm; + + location / { + try_files \$uri \$uri/ /index.php?\$args; + } + + location ~ \.php$ { + include snippets/fastcgi-php.conf; + 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; + } +} +EOF + + # Enable Nginx site and disable default + ln -s /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" +} + +# Get Let's Encrypt certificates +get_ssl_certificates() { + info "Obtaining Let's Encrypt certificates..." + + # Use certbot with the nginx plugin. It will automatically update the Nginx config for HTTPS. + certbot --nginx -d $HOSTNAME --email $ADMIN_EMAIL --agree-tos --non-interactive + + if [[ ! -f "/etc/letsencrypt/live/$HOSTNAME/fullchain.pem" ]]; then + error "Failed to obtain SSL certificate" + fi + + # Certbot automatically sets up a cronjob for renewal with the nginx plugin + success "SSL certificates obtained and Nginx configured for HTTPS" +} + +# --- +# The rest of the script is largely unchanged, but the main function has been reordered. +# --- + # Configure Postfix configure_postfix() { info "Configuring Postfix..." - + # Backup original configuration cp /etc/postfix/main.cf /etc/postfix/main.cf.backup - + # Create main.cf cat > /etc/postfix/main.cf << EOF # Basic configuration @@ -307,7 +406,7 @@ mydestination = localhost virtual_mailbox_domains = pgsql:/etc/postfix/pgsql-virtual-mailbox-domains.cf virtual_mailbox_maps = pgsql:/etc/postfix/pgsql-virtual-mailbox-maps.cf virtual_alias_maps = pgsql:/etc/postfix/pgsql-virtual-alias-maps.cf -virtual_mailbox_base = $MAIL_VOLUME_PATH/vhosts # <-- CHANGED: Mailbox base is now the volume path +virtual_mailbox_base = $MAIL_VOLUME_PATH/vhosts virtual_minimum_uid = 100 virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 @@ -377,75 +476,23 @@ EOF # Set permissions chmod 640 /etc/postfix/pgsql-*.cf chown root:postfix /etc/postfix/pgsql-*.cf - - # Configure master.cf for submission and smtps - cat >> /etc/postfix/master.cf << EOF - -# Submission port 587 -submission inet n - y - - smtpd - -o syslog_name=postfix/submission - -o smtpd_tls_security_level=encrypt - -o smtpd_sasl_auth_enable=yes - -o smtpd_sasl_type=dovecot - -o smtpd_sasl_path=private/auth - -o smtpd_reject_unlisted_recipient=no - -o smtpd_client_restrictions=permit_sasl_authenticated,reject - -o milter_macro_daemon_name=ORIGINATING - -# SMTPS port 465 -smtps inet n - y - - smtpd - -o syslog_name=postfix/smtps - -o smtpd_tls_wrappermode=yes - -o smtpd_sasl_auth_enable=yes - -o smtpd_sasl_type=dovecot - -o smtpd_sasl_path=private/auth - -o smtpd_client_restrictions=permit_sasl_authenticated,reject - -o milter_macro_daemon_name=ORIGINATING - -# Amavis -smtp-amavis unix - - - - 2 smtp - -o smtp_data_done_timeout=1200 - -o smtp_send_xforward_command=yes - -o disable_dns_lookups=yes - -o max_use=20 - -127.0.0.1:10025 inet n - - - - smtpd - -o content_filter= - -o local_recipient_maps= - -o relay_recipient_maps= - -o smtpd_restriction_classes= - -o smtpd_delay_reject=no - -o smtpd_client_restrictions=permit_mynetworks,reject - -o smtpd_helo_restrictions= - -o smtpd_sender_restrictions= - -o smtpd_recipient_restrictions=permit_mynetworks,reject - -o smtpd_data_restrictions=reject_unauth_pipelining - -o smtpd_end_of_data_restrictions= - -o mynetworks=127.0.0.0/8 - -o smtpd_error_sleep_time=0 - -o smtpd_soft_error_limit=1001 - -o smtpd_hard_error_limit=1000 - -o smtpd_client_connection_count_limit=0 - -o smtpd_client_connection_rate_limit=0 - -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks -EOF # Create virtual mailbox directory and set permissions - mkdir -p $MAIL_VOLUME_PATH/vhosts # <-- CHANGED: Directory is now created on the volume + mkdir -p $MAIL_VOLUME_PATH/vhosts groupadd -g 5000 vmail 2>/dev/null || true useradd -g vmail -u 5000 vmail -d $MAIL_VOLUME_PATH/vhosts -m 2>/dev/null || true - chown -R vmail:vmail $MAIL_VOLUME_PATH/vhosts # <-- CHANGED: Permissions set on the volume - + chown -R vmail:vmail $MAIL_VOLUME_PATH/vhosts + success "Postfix configured" } # Configure Dovecot configure_dovecot() { info "Configuring Dovecot..." - + # Backup configuration cp -r /etc/dovecot /etc/dovecot.backup - + # Main configuration cat > /etc/dovecot/dovecot.conf << EOF !include_try /usr/share/dovecot/protocols.d/*.protocol @@ -456,7 +503,7 @@ EOF # 10-mail.conf cat > /etc/dovecot/conf.d/10-mail.conf << EOF -mail_location = maildir:$MAIL_VOLUME_PATH/vhosts/%d/%n # <-- CHANGED: Mail location is now the volume path +mail_location = maildir:$MAIL_VOLUME_PATH/vhosts/%d/%n namespace inbox { inbox = yes } @@ -484,7 +531,7 @@ passdb { } userdb { driver = static - args = uid=vmail gid=vmail home=$MAIL_VOLUME_PATH/vhosts/%d/%n # <-- CHANGED: User home directory is now on the volume + args = uid=vmail gid=vmail home=$MAIL_VOLUME_PATH/vhosts/%d/%n } EOF @@ -558,28 +605,28 @@ EOF # Generate DH parameters openssl dhparam -out /etc/dovecot/dh.pem 2048 - + # Set permissions chmod 600 /etc/dovecot/dovecot-sql.conf.ext chown vmail:dovecot /etc/dovecot/dovecot-sql.conf.ext - + success "Dovecot configured" } # Configure OpenDKIM configure_opendkim() { info "Configuring OpenDKIM..." - + # Create directories mkdir -p /etc/opendkim/keys/$DOMAIN - + # Generate DKIM key opendkim-genkey -t -s mail -d $DOMAIN -D /etc/opendkim/keys/$DOMAIN - + # Set permissions chown -R opendkim:opendkim /etc/opendkim chmod 600 /etc/opendkim/keys/$DOMAIN/mail.private - + # OpenDKIM configuration cat > /etc/opendkim.conf << EOF Syslog yes @@ -597,10 +644,10 @@ EOF # Key table echo "mail._domainkey.$DOMAIN $DOMAIN:mail:/etc/opendkim/keys/$DOMAIN/mail.private" > /etc/opendkim/key.table - + # Signing table echo "*@$DOMAIN mail._domainkey.$DOMAIN" > /etc/opendkim/signing.table - + # Trusted hosts cat > /etc/opendkim/trusted.hosts << EOF 127.0.0.1 @@ -610,7 +657,7 @@ $DOMAIN EOF success "OpenDKIM configured" - + # Display DNS record info "Add this TXT record to your DNS:" echo "mail._domainkey.$DOMAIN" @@ -620,10 +667,10 @@ EOF # Configure Amavis and SpamAssassin configure_amavis() { info "Configuring Amavis and SpamAssassin..." - + # Update ClamAV signatures freshclam - + # Configure Amavis cat > /etc/amavis/conf.d/15-content_filter_mode << 'EOF' use strict; @@ -695,131 +742,24 @@ EOF # Add amavis user to clamav group usermod -a -G clamav amavis - + success "Amavis and SpamAssassin configured" } -# Install PostfixAdmin -install_postfixadmin() { - info "Installing PostfixAdmin..." - - # Download PostfixAdmin - cd /tmp - wget -q https://github.com/postfixadmin/postfixadmin/archive/$POSTFIXADMIN_VERSION || error "Failed to download PostfixAdmin" - tar -xzf $POSTFIXADMIN_VERSION - mv postfixadmin-postfixadmin-3.3.11 $WEBROOT - - # Set permissions - chown -R www-data:www-data $WEBROOT - find $WEBROOT -type d -exec chmod 755 {} \; - find $WEBROOT -type f -exec chmod 644 {} \; - - # Create PostfixAdmin configuration - cat > $WEBROOT/config.local.php << EOF - 'abuse@change-this-to-your.domain.tld', - 'hostmaster' => 'hostmaster@change-this-to-your.domain.tld', - 'postmaster' => 'postmaster@change-this-to-your.domain.tld', - 'webmaster' => 'webmaster@change-this-to-your.domain.tld' -); -\$CONF['domain_path'] = 'YES'; -\$CONF['domain_in_mailbox'] = 'YES'; -\$CONF['maildir_name_hook'] = 'maildir_name_hook'; -function maildir_name_hook(\$domain, \$user) { - return \$domain . '/' . \$user . '/'; -} -?> -EOF - - # Configure Nginx virtual host for PostfixAdmin - cat > /etc/nginx/sites-available/postfixadmin.conf << EOF -server { - listen 80; - server_name $HOSTNAME; - return 301 https://\$server_name\$request_uri; -} - -server { - listen 443 ssl http2; - server_name $HOSTNAME; - - root $WEBROOT/public; - index index.php index.html index.htm; - - location / { - try_files \$uri \$uri/ /index.php?\$args; - } - - location ~ \.php$ { - include snippets/fastcgi-php.conf; - 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; - } - - # SSL configuration, to be updated by Certbot - ssl_certificate /etc/letsencrypt/live/$HOSTNAME/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/$HOSTNAME/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/$HOSTNAME/chain.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; -} -EOF - - # Enable Nginx site and disable default - ln -s /etc/nginx/sites-available/postfixadmin.conf /etc/nginx/sites-enabled/ - rm /etc/nginx/sites-enabled/default - - # Reload Nginx to apply changes - systemctl reload nginx - - success "PostfixAdmin installed and Nginx configured" -} - -# Get Let's Encrypt certificates -get_ssl_certificates() { - info "Obtaining Let's Encrypt certificates..." - - # Use certbot with the nginx plugin - certbot --nginx -d $HOSTNAME --email $ADMIN_EMAIL --agree-tos --non-interactive - - if [[ ! -f "/etc/letsencrypt/live/$HOSTNAME/fullchain.pem" ]]; then - error "Failed to obtain SSL certificate" - fi - - # Certbot automatically sets up a cronjob for renewal with the nginx plugin - - success "SSL certificates obtained and Nginx configured for HTTPS" -} - # 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 @@ -828,24 +768,24 @@ configure_firewall() { 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..." - + # Reload systemd systemctl daemon-reload - + # Start and enable services systemctl enable --now postgresql systemctl enable --now postfix @@ -857,7 +797,7 @@ start_services() { systemctl enable --now opendkim systemctl enable --now nginx systemctl enable --now php$(php -r "echo PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;")-fpm - + success "All services started and enabled" } @@ -869,7 +809,7 @@ display_final_info() { echo "Primary Domain: $DOMAIN" echo "Hostname: $HOSTNAME" echo "Admin Email: $ADMIN_EMAIL" - echo "Mailbox Location: $MAIL_VOLUME_PATH/vhosts" # <-- CHANGED: Display the new path + echo "Mailbox Location: $MAIL_VOLUME_PATH/vhosts" echo "PostfixAdmin URL: https://$HOSTNAME/postfixadmin/" echo echo -e "${YELLOW}=== DNS Records to Add for $DOMAIN ===${NC}" @@ -918,20 +858,20 @@ main() { echo -e "${BLUE}Email Server Setup Script${NC}" echo "=========================" echo - + check_root get_configuration update_system install_packages configure_postgresql install_postfixadmin - get_ssl_certificates + start_services # <-- Nginx is started here with a basic HTTP config + get_ssl_certificates # <-- Certbot is now run after Nginx is active configure_postfix configure_dovecot configure_opendkim configure_amavis configure_firewall - start_services display_final_info }