#!/bin/bash # Exit on any error set -e # Function to log messages log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # Check if script is run as root if [ "$EUID" -ne 0 ]; then echo "Please run as root" exit 1 fi # Update system log_message "Updating system packages..." apt-get update && apt-get upgrade -y # Install essential packages log_message "Installing essential packages..." apt-get install -y \ ca-certificates \ curl \ gnupg \ ufw \ fail2ban \ git \ sudo # Install Docker log_message "Installing Docker..." install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc # Add Docker repository echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Create docker user and set up permissions log_message "Creating docker user and setting up permissions..." useradd -m -s /bin/bash dockeruser usermod -aG docker dockeruser echo "dockeruser ALL=(ALL) NOPASSWD: /usr/bin/docker, /usr/bin/docker-compose" | sudo tee /etc/sudoers.d/dockeruser # Configure UFW log_message "Configuring firewall..." ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp ufw allow 25/tcp ufw allow 80/tcp ufw allow 110/tcp ufw allow 143/tcp ufw allow 443/tcp ufw allow 465/tcp ufw allow 587/tcp ufw allow 993/tcp ufw allow 995/tcp ufw allow 4190/tcp ufw --force enable # Configure fail2ban with SSH honeypot log_message "Configuring fail2ban and SSH honeypot..." cat > /etc/fail2ban/jail.local << EOL [DEFAULT] bantime = 1h findtime = 10m maxretry = 3 banaction = ufw backend = systemd ignoreip = 127.0.0.1/8 ::1 findtime = 10m bantime = 1h maxretry = 3 [sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_log)s maxretry = 3 bantime = 1d [ssh-honeypot] enabled = true filter = sshd logpath = %(sshd_log)s maxretry = 1 bantime = 1d findtime = 1d EOL # Configure fail2ban filter cat > /etc/fail2ban/filter.d/sshd.local << EOL [Definition] failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from ( via \S+)?\s*$ ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from \s*$ ^%(__prefix_line)sFailed \S+ for .* from (?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s))?\s*$ ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM \s*$ ^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from \s*$ ^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s*$ ^%(__prefix_line)sUser .+ from not allowed because listed in DenyUsers\s*$ ^%(__prefix_line)sUser .+ from not allowed because not in any group\s*$ ^%(__prefix_line)srefused connect from \S+ \(\)\s*$ ^%(__prefix_line)sReceived disconnect from : 3: .*: Auth fail$ ^%(__prefix_line)sUser .+ from not allowed because a group is listed in DenyGroups\s*$ ^%(__prefix_line)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*$ ^%(__prefix_line)s[aA]uthentication (?:failure|error) for .* from (?:\s+\[preauth\])?\s*$ ignoreregex = EOL # Create fail2ban systemd override directory mkdir -p /etc/systemd/system/fail2ban.service.d/ # Create override file cat > /etc/systemd/system/fail2ban.service.d/override.conf << EOL [Service] ExecStart= ExecStart=/usr/bin/fail2ban-server -xf start EOL # Reload systemd daemon systemctl daemon-reload # Restart fail2ban systemctl restart fail2ban # Set up Mailcow directory and permissions log_message "Setting up Mailcow directory..." mkdir -p /opt/mailcow-dockerized chown dockeruser:dockeruser /opt/mailcow-dockerized # Switch to dockeruser and install Mailcow log_message "Installing Mailcow as dockeruser..." su - dockeruser << 'EOF' cd /opt git clone https://github.com/mailcow/mailcow-dockerized cd mailcow-dockerized ./generate_config.sh # Start Mailcow docker compose pull docker compose up -d EOF # Final security checks log_message "Performing final security checks..." su - dockeruser -c "cd /opt/mailcow-dockerized && docker compose ps" ufw status systemctl status fail2ban log_message "Installation complete! Please check the logs above for any errors." log_message "Remember to:" log_message "1. Change the default passwords" log_message "2. Configure your DNS records" log_message "3. Set up SSL certificates" log_message "4. Regular backup your configuration" # Print access information echo "================================================================" echo "Mailcow web interface: https://$(hostname)" echo "Docker user: dockeruser" echo "Mailcow location: /opt/mailcow-dockerized" echo "Firewall status:" ufw status numbered echo "================================================================"