This tutorial will show you how to take a fresh Ubuntu 16.04 LTS VPS and turn it into a web and email server for a single domain. Many VPS providers offer $5 solutions with 1GB of RAM and 1 vCPU. This is more than enough.
The full script is available at the end of this post. Between here and there, I’m going to explain the different sections of the bash file, and what you need to change.
Step 0: Header
At the beginning of our bash file we have some header items.
1 2 3 4 5 |
#!/bin/bash RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' NC='\033[0m' # No Color |
Step 1: Allow you to SSH in as root with your key.
Some providers, like DigitalOcean, automatically add your SSH key to the root user, so you don’t need this step. However, others like Linode do not. If you need you add your SSH key, use the template below.
7 8 9 10 11 12 13 |
#setup ssh for root mkdir -p /root/.ssh chmod 700 /root/.ssh touch /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys echo "ssh-rsa AAAA.... ssh@key.here" >> "/root/.ssh/authorized_keys" service ssh restart |
Line 12 will place your SSH key into the authorized_keys for root. Be sure to add your key.
Step 2: Remove Snaps
Newer Ubuntu installations come with snaps. They are handy, if that’s what you want. We don’t, however.
15 16 17 18 19 20 21 22 23 24 25 26 27 |
#Remove the snapd echo -e "${CYAN}Removing snapd.${NC}" systemctl disable snapd.refresh.service systemctl disable snapd.refresh.timer systemctl disable snapd.autoimport.service systemctl disable snapd.core-fixup.service systemctl disable snapd.service systemctl disable snapd.snap-repair.timer systemctl disable snapd.socket systemctl disable snapd.system-shutdown.service apt remove snapd -y apt purge snapd ubuntu-core-launcher squashfs-tools -y echo -e "${GREEN}Done.${NC}" |
Step 3: Create swap file
This will create a 2GB swap file on the disk for us. The exact size of this depends on the server you are running. Some VPS providers set you up with one out of the box. This is optional, if it’s a small site with minimal database usage, you probably don’t need this.
29 30 31 32 33 34 35 36 37 |
#Create a swapfile echo -e "${CYAN}Creating a swap file.${NC}" fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile cp /etc/fstab /etc/fstab.bak echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab echo -e "${GREEN}Done.${NC}" |
Step 4: Add new repos for CertBot and newest PHP
Ubuntu, out-of-the-box, does not have the repositories that contain CertBot or PHP 7.2. (As of the time of writing) We need to add them.
UPDATE (20 Apr 2018): I’ve changed the order of this script and added the software-properties-common. While Digital Ocean had that package installed, Linode did not.
39 40 41 42 43 44 45 46 47 48 |
#Add the new repos echo -e "${CYAN}Updating the repositories.${NC}" apt-get update apt-get install -y software-properties-common add-apt-repository -y ppa:certbot/certbot add-apt-repository -y ppa:ondrej/php apt-get update apt-get upgrade -y apt-get autoremove -y echo -e "${GREEN}Done.${NC}" |
Step 5: Install Software
This will install Apache, CertBot, PHP 7.2, MySQL, Postfix, Dovecot, and OpenDKIM, as well as their modules.
Apache
50 51 52 53 54 55 56 |
#Install Apache2 echo -e "${CYAN}Installing Apache2.${NC}" apt-get install -y apache2 apache2-bin apache2-data apache2-utils a2dismod mpm_event a2enmod mpm_prefork actions headers proxy proxy_http rewrite socache_shmcb ssl service apache2 restart echo -e "${GREEN}Done.${NC}" |
CertBot
58 59 60 61 |
#Install Certbot echo -e "${CYAN}Installing CertBot.${NC}" apt-get install -y apt-transport-https software-properties-common python-certbot-apache python-software-properties echo -e "${GREEN}Done.${NC}" |
PHP
I have commented out the install command for 7.0 and 7.1, leaving 7.2 to be installed. If you need a different version, feel free to change this.
63 64 65 66 67 68 |
#Install PHP echo -e "${CYAN}Installing PHP.${NC}" #apt-get install -y php7.0 php7.0-cgi php7.0-cli php7.0-curl php7.0-gd php7.0-gmp php7.0-json php7.0-mysql php7.0-xml libapache2-mod-php7.0 php7.0-mbstring php7.0-soap php7.0-zip php7.0-xsl php7.0-bcmath php7.0-bz2 php7.0-common php7.0-mcrypt #apt-get install -y php7.1 php7.1-cgi php7.1-cli php7.1-curl php7.1-gd php7.1-gmp php7.1-json php7.1-mysql php7.1-xml libapache2-mod-php7.1 php7.1-mbstring php7.1-soap php7.1-zip php7.1-xsl php7.1-bcmath php7.1-bz2 php7.1-common php7.1-mcrypt apt-get install -y php7.2 php7.2-cgi php7.2-cli php7.2-curl php7.2-gd php7.2-gmp php7.2-json php7.2-mysql php7.2-xml libapache2-mod-php7.2 php7.2-mbstring php7.2-soap php7.2-zip php7.2-xsl php7.2-bcmath php7.2-bz2 php7.2-common echo -e "${GREEN}Done.${NC}" |
MySQL
When MySQL installs, you will need to set up a root password.
70 71 72 73 |
#Install MySQL echo -e "${CYAN}Installing MySQL.${NC}" apt-get install -y mysql-server echo -e "${GREEN}Done.${NC}" |
Postfix, Dovecot, and OpenDKIM
When Postfix installs, you will need to answer two questions. The first, you are installing it on an internet site; and the second, put in the domain, like example.com or lupecode.com.
75 76 77 78 |
#Install Postfix, Dovecot and OpenDKIM echo -e "${CYAN}Installing Postfix, Dovecot and OpenDKIM${NC}" apt-get install -y postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql opendkim opendkim-tools echo -e "${GREEN}Done.${NC}" |
Step 6: Set the domain variable.
To make your editing a little easier, we will store the domain, like example.com or lupecode.com, in a console variable.
We’ll also save it so the new site script can use it.
UPDATE (20 Apr 2018): I’ve had to add the update of the hostname. Digital Ocean does this when the instance is spun up, but Linode does not.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#Setup the single site server echo -e "${CYAN}Enter the domain of the new server: ${NC}" read domain echo -e "$domain" >> /root/domain echo -e "$domain" >> /etc/hostname hostname "$domain" hostnamectl set-hostname "$domain" mkdir "/var/www/$domain" echo -e "${CYAN}Enter the name of the mail server database: ${NC}" read maildatabase echo -e "${CYAN}Enter the username for the mail server database: ${NC}" read mailuser echo -e "${CYAN}Enter the password for $mailuser: ${NC}" read mailpass echo -e "${CYAN}Enter the password for the mail box admin@$domain: ${NC}" read adminpassword |
Step 7: Setup Certbot
Now we want to activate CertBot to get a wildcard certificate for our domain.
You will need to update your DNS records by hand.
You will also need to have the domain, like example.com or lupecode.com, pointing to the server already as you will need to create a challenge file.
97 98 99 100 |
#CertBot get the wildcard certificate echo -e "${CYAN}Setting up Certbot${NC}" certbot certonly --manual --domain "$domain" --domain "*.$domain" --server https://acme-v02.api.letsencrypt.org/directory echo -e "${GREEN}Done.${NC}" |
Step 8: Configure Apache
We added our domain as a variable to the console, so you can just copy these four cats. They set up the domain with a SSL site and reditect the non-SSL. HSTS is also included, as well as a sweet landing page.
1 2 |
#Setup Apache2 echo -e "${CYAN}Setting up Apache config${NC}" |
The /var/www/$domain/index.html
file
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
cat > "/var/www/$domain/index.html" <<EOF <!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>$domain</title> <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css"> <style> html, body {background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0;} .full-height {height: 100vh;} .flex-center {align-items: center; display: flex; justify-content: center;} .position-ref {position: relative;} .top-right {position: absolute; right: 10px; top: 18px;} .content {text-align: center;} .title {font-size: 84px;} .links > a {color: #636b6f;padding: 0 25px;font-size: 12px;font-weight: 600;letter-spacing: .1rem;text-decoration: none;text-transform: uppercase;} .m-b-md {margin-bottom: 30px;} </style> </head> <body> <div class="flex-center position-ref full-height"> <div class="content"> <div class="title m-b-md">$domain</div> </div> </div> </body> </html> EOF |
The /etc/apache2/sites-available/000-default.conf
file
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
cat > "/etc/apache2/sites-available/000-default.conf" <<EOF <VirtualHost *:80> DocumentRoot "/var/www/$domain" ErrorLog \${APACHE_LOG_DIR}/error.log CustomLog \${APACHE_LOG_DIR}/access.log combined ServerAdmin webmaster@$domain <Directory "/var/www/$domain"> AllowOverride All allow from all Options +Indexes </Directory> RewriteEngine on RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] </VirtualHost> EOF |
The /etc/apache2/sites-available/000-default-le-ssl.conf
file
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
cat > "/etc/apache2/sites-available/000-default-le-ssl.conf" <<EOF <IfModule mod_ssl.c> <VirtualHost *:443> DocumentRoot "/var/www/$domain" <Directory "/var/www/$domain"> AllowOverride All allow from all Options +Indexes </Directory> SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf Header always set Strict-Transport-Security "max-age=31536000" </VirtualHost> </IfModule> EOF |
The /etc/letsencrypt/options-ssl-apache.conf
file
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
cat > "/etc/letsencrypt/options-ssl-apache.conf" <<EOF # This file contains important security parameters. If you modify this file # manually, Certbot will be unable to automatically provide future security # updates. Instead, Certbot will print and log an error message with a path to # the up-to-date file that you will need to refer to when manually updating # this file. SSLEngine on # Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS SSLHonorCipherOrder on SSLCompression off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common #CustomLog /var/log/apache2/access.log vhost_combined #LogLevel warn #ErrorLog /var/log/apache2/error.log # Always ensure Cookies have "Secure" set (JAH 2012/1) #Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "\$1; Secure\$3\$4" EOF |
And restart Apache.
194 195 196 197 198 199 200 201 202 |
echo -e "${GREEN}Done.${NC}" #Restart Apache2 echo -e "${CYAN}Restarting Apache${NC}" a2ensite 000-default-le-ssl chown -R www-data:www-data /var/www service apache2 restart rm -rf /var/www/html echo -e "${GREEN}Done.${NC}" |
Step 9: Setup Postfix.
There will be multiple files here as well.
205 |
echo -e "${CYAN}Configuring Postfix${NC}" |
The /etc/postfix/main.cf
file
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
cat > "/etc/postfix/main.cf" <<EOF smtpd_banner = $domain ESMTP biff = no append_dot_mydomain = no readme_directory = no smtpd_tls_cert_file = /etc/letsencrypt/live/$domain/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/$domain/privkey.pem smtpd_use_tls = yes smtpd_tls_session_cache_database = btree:\${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:\${data_directory}/smtp_scache smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination myhostname = $domain alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = /etc/mailname mydestination = localhost relayhost = mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all inet_protocols = all smtpd_tls_auth_only = yes smtp_tls_security_level = may smtpd_tls_security_level = may smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-virtual-email2email.cf milter_protocol = 2 milter_default_action = accept smtpd_milters = inet:localhost:12301 non_smtpd_milters = inet:localhost:12301 EOF |
The /etc/postfix/master.cf
file
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
cat > "/etc/postfix/master.cf" <<EOF smtp inet n - y - - smtpd submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=no -o milter_macro_daemon_name=ORIGINATING smtps inet n - y - - smtpd -o syslog_name=postfix/smtps -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=no -o milter_macro_daemon_name=ORIGINATING pickup unix n - y 60 1 pickup cleanup unix n - y - 0 cleanup qmgr unix n - n 300 1 qmgr tlsmgr unix - - y 1000? 1 tlsmgr rewrite unix - - y - - trivial-rewrite bounce unix - - y - 0 bounce defer unix - - y - 0 bounce trace unix - - y - 0 bounce verify unix - - y - 1 verify flush unix n - y 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - y - - smtp relay unix - - y - - smtp showq unix n - y - - showq error unix - - y - - error retry unix - - y - - error discard unix - - y - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - y - - lmtp anvil unix - - y - 1 anvil scache unix - - y - 1 scache maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d \${recipient} uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a\$sender - \$nexthop!rmail (\$recipient) ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r \$nexthop (\$recipient) bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t\$nexthop -f\$sender \$recipient scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store \${nexthop} \${user} \${extension} mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py \${nexthop} \${user} EOF |
The /etc/postfix/mysql-virtual-mailbox-domains.cf
file
295 296 297 298 299 300 301 |
cat > "/etc/postfix/mysql-virtual-mailbox-domains.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT 1 FROM virtual_domains WHERE name='%s' EOF |
The /etc/postfix/mysql-virtual-alias-maps.cf
file
302 303 304 305 306 307 308 |
cat > "/etc/postfix/mysql-virtual-alias-maps.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT destination FROM virtual_aliases WHERE source='%s' EOF |
The /etc/postfix/mysql-virtual-mailbox-maps.cf
file
309 310 311 312 313 314 315 |
cat > "/etc/postfix/mysql-virtual-mailbox-maps.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT 1 FROM virtual_users WHERE email='%s' EOF |
The /etc/postfix/mysql-virtual-email2email.cf
file
316 317 318 319 320 321 322 |
cat > "/etc/postfix/mysql-virtual-email2email.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT email FROM virtual_users WHERE email='%s' EOF |
That’s finished.
323 |
echo -e "${GREEN}Done.${NC}" |
Step 10: Setup MySQL Database
We’re going to create an SQL file and run it!
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
#Configure MySQL echo -e "${CYAN}Configuring MySQL${NC}" cat > "/root/email_mysql.sql" <<EOF DROP DATABASE IF EXISTS $maildatabase; CREATE DATABASE $maildatabase; USE $maildatabase; GRANT ALL ON $maildatabase.* TO '$mailuser'@'localhost' IDENTIFIED BY '$mailpass'; FLUSH PRIVILEGES; CREATE TABLE `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `password` varchar(106) NOT NULL, `email` varchar(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `destination_id` int(11) NULL, `source` varchar(100) NOT NULL, `destination` varchar(100) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE, FOREIGN KEY (destination_id) REFERENCES virtual_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `$maildatabase`.`virtual_domains` (`id` ,`name`) VALUES ('1', '$domain'); INSERT INTO `$maildatabase`.`virtual_users` (`id`, `domain_id`, `password` , `email`) VALUES ('1', '1', ENCRYPT('$adminpassword', CONCAT('\$6$', SUBSTRING(SHA(RAND()), -16))), 'admin@$domain'); INSERT INTO `$maildatabase`.`virtual_aliases` (`id`, `domain_id`, `destination_id`, `source`, `destination`) VALUES ('1', '1', '1', '@$domain', 'admin@$domain'); EOF mysql -u root -p < "/root/email_mysql.sql" echo -e "${GREEN}Done.${NC}" |
You will have the database prepped with the domain, an admin@ account with the password you set before, and a catchall forwarding to the admin@ account.
Step 11: Dovecot Setup
First we need to add the vmail user.
364 365 366 367 368 369 |
#Configure Dovecot echo -e "${CYAN}Configuring Dovecot${NC}" mkdir -p "/var/mail/vhosts/$domain" groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/mail chown -R vmail:vmail /var/mail |
The /etc/dovecot/dovecot.conf
file
370 371 372 373 374 375 |
cat > "/etc/dovecot/dovecot.conf" <<EOF !include_try /usr/share/dovecot/protocols.d/*.protocol protocols = imap pop3 lmtp !include conf.d/*.conf !include_try local.conf EOF |
The /etc/dovecot/conf.d/10-mail.conf
file
376 377 378 379 380 381 382 |
cat > "/etc/dovecot/conf.d/10-mail.conf" <<EOF mail_location = maildir:/var/mail/vhosts/%d/%n namespace inbox { inbox = yes } mail_privileged_group = mail EOF |
The /etc/dovecot/conf.d/10-auth.conf
file
383 384 385 386 387 |
cat > "/etc/dovecot/conf.d/10-auth.conf" <<EOF disable_plaintext_auth = yes auth_mechanisms = plain login !include auth-sql.conf.ext EOF |
The /etc/dovecot/conf.d/auth-sql.conf.ext
file
388 389 390 391 392 393 394 395 396 397 398 |
cat > "/etc/dovecot/conf.d/auth-sql.conf.ext" <<EOF passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = static args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n } EOF |
The /etc/dovecot/dovecot-sql.conf.ext
file
399 400 401 402 403 404 |
cat > "/etc/dovecot/dovecot-sql.conf.ext" <<EOF driver = mysql connect = host=127.0.0.1 dbname=$maildatabase user=$mailuser password=$mailpass default_pass_scheme = SHA512-CRYPT password_query = SELECT email as user, password FROM virtual_users WHERE email='%u'; EOF |
The /etc/dovecot/conf.d/10-master.conf
file
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
cat > "/etc/dovecot/conf.d/10-master.conf" <<EOF service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 ssl = yes } } service pop3-login { inet_listener pop3 { port = 0 } inet_listener pop3s { port = 995 ssl = yes } } service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } } service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } unix_listener auth-userdb { mode = 0600 user = vmail } user = dovecot } service auth-worker { user = vmail } EOF |
The /etc/dovecot/conf.d/10-ssl.conf
file
447 448 449 450 451 |
cat > "/etc/dovecot/conf.d/10-ssl.conf" <<EOF ssl = required ssl_cert = <//etc/letsencrypt/live/$domain/fullchain.pem ssl_key = </etc/letsencrypt/live/$domain/privkey.pem EOF |
And restart Dovecot
452 453 454 |
chown -R vmail:dovecot /etc/dovecot service dovecot restart echo -e "${GREEN}Done.${NC}" |
Step 12: OpenDKIM Setup
First we will need a few directories.
456 457 458 459 460 |
#Configure DKIM echo -e "${CYAN}Configuring DKIM${NC}" mkdir /etc/opendkim mkdir /etc/opendkim/keys mkdir /etc/opendkim/keys/$domain |
Then some config files.
The /etc/opendkim.conf
file
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
cat > "/etc/opendkim.conf" <<EOF Syslog yes Domain * Selector mail AutoRestart Yes Background yes Canonicalization relaxed/simple DNSTimeout 5 Mode sv SignatureAlgorithm rsa-sha256 Statistics /var/log/dkim-filter/dkim-stats UMask 002 AutoRestartRate 10/1h SyslogSuccess Yes LogWhy Yes ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable PidFile /var/run/opendkim/opendkim.pid Socket inet:12301@localhost EOF |
The /etc/default/opendkim
file
484 485 486 487 |
cat > "/etc/default/opendkim" <<EOF SOCKET="local:/var/run/opendkim/opendkim.sock" SOCKET="inet:12301@localhost" EOF |
The /etc/opendkim/TrustedHosts
file
488 489 490 491 492 493 |
cat > "/etc/opendkim/TrustedHosts" <<EOF 127.0.0.1 localhost $domain *.$domain EOF |
The /etc/opendkim/KeyTable
file
494 495 496 |
cat > "/etc/opendkim/KeyTable" <<EOF mail._domainkey.$domain $domain:mail:/etc/opendkim/keys/$domain/mail.private EOF |
The /etc/opendkim/SigningTable
file
497 498 499 |
cat > "/etc/opendkim/SigningTable" <<EOF *@$domain mail._domainkey.$domain EOF |
And now to generate the key.
500 501 502 503 504 |
opendkim-genkey -s mail -d $domain -D /etc/opendkim/keys/$domain chown opendkim:opendkim /etc/opendkim/keys/$domain/mail.private mkdir /var/log/dkim-filter touch /var/log/dkim-filter/dkim-stats chown -R opendkim:opendkim /var/log/dkim-filter |
And restart Postfix and OpenDKIM
505 506 507 508 509 |
service postfix restart service opendkim restart echo -e "${GREEN}Done.${NC}" echo -e "${CYAN}The installation script has finished.${NC}" echo -e "${RED}PLEASE REBOOT THIS SERVER.${NC}" |
Step 13: DNS
You will want to take the DNS record in /etc/opendkim/keys/$domain/mail.txt
and add it to your DNS. This is the last step to get DKIM to work.
Summary
I have this entire thing as a shell file for those that want it. Just be sure to change the SSH key near the top.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
#!/bin/bash RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' NC='\033[0m' # No Color #setup ssh for root mkdir -p /root/.ssh chmod 700 /root/.ssh touch /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys echo "ssh-rsa AAAA... ssh@key.here" >> "/root/.ssh/authorized_keys" service ssh restart #Remove the snapd echo -e "${CYAN}Removing snapd.${NC}" systemctl disable snapd.refresh.service systemctl disable snapd.refresh.timer systemctl disable snapd.autoimport.service systemctl disable snapd.core-fixup.service systemctl disable snapd.service systemctl disable snapd.snap-repair.timer systemctl disable snapd.socket systemctl disable snapd.system-shutdown.service apt remove snapd -y apt purge snapd ubuntu-core-launcher squashfs-tools -y echo -e "${GREEN}Done.${NC}" #Create a swapfile echo -e "${CYAN}Creating a swap file.${NC}" fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile cp /etc/fstab /etc/fstab.bak echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab echo -e "${GREEN}Done.${NC}" #Add the new repos echo -e "${CYAN}Updating the repositories.${NC}" apt-get update apt-get install -y software-properties-common add-apt-repository -y ppa:certbot/certbot add-apt-repository -y ppa:ondrej/php apt-get update apt-get upgrade -y apt-get autoremove -y echo -e "${GREEN}Done.${NC}" #Install Apache2 echo -e "${CYAN}Installing Apache2.${NC}" apt-get install -y apache2 apache2-bin apache2-data apache2-utils a2dismod mpm_event a2enmod mpm_prefork actions headers proxy proxy_http rewrite socache_shmcb ssl service apache2 restart echo -e "${GREEN}Done.${NC}" #Install Certbot echo -e "${CYAN}Installing CertBot.${NC}" apt-get install -y apt-transport-https software-properties-common python-certbot-apache python-software-properties echo -e "${GREEN}Done.${NC}" #Install PHP echo -e "${CYAN}Installing PHP.${NC}" #apt-get install -y php7.0 php7.0-cgi php7.0-cli php7.0-curl php7.0-gd php7.0-gmp php7.0-json php7.0-mysql php7.0-xml libapache2-mod-php7.0 php7.0-mbstring php7.0-soap php7.0-zip php7.0-xsl php7.0-bcmath php7.0-bz2 php7.0-common php7.0-mcrypt #apt-get install -y php7.1 php7.1-cgi php7.1-cli php7.1-curl php7.1-gd php7.1-gmp php7.1-json php7.1-mysql php7.1-xml libapache2-mod-php7.1 php7.1-mbstring php7.1-soap php7.1-zip php7.1-xsl php7.1-bcmath php7.1-bz2 php7.1-common php7.1-mcrypt apt-get install -y php7.2 php7.2-cgi php7.2-cli php7.2-curl php7.2-gd php7.2-gmp php7.2-json php7.2-mysql php7.2-xml libapache2-mod-php7.2 php7.2-mbstring php7.2-soap php7.2-zip php7.2-xsl php7.2-bcmath php7.2-bz2 php7.2-common echo -e "${GREEN}Done.${NC}" #Install MySQL echo -e "${CYAN}Installing MySQL.${NC}" apt-get install -y mysql-server echo -e "${GREEN}Done.${NC}" #Install Postfix, Dovecot and OpenDKIM echo -e "${CYAN}Installing Postfix, Dovecot and OpenDKIM${NC}" apt-get install -y postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql opendkim opendkim-tools echo -e "${GREEN}Done.${NC}" #Setup the single site server echo -e "${CYAN}Enter the domain of the new server: ${NC}" read domain echo -e "$domain" >> /root/domain echo -e "$domain" >> /etc/hostname hostname "$domain" hostnamectl set-hostname "$domain" mkdir "/var/www/$domain" echo -e "${CYAN}Enter the name of the mail server database: ${NC}" read maildatabase echo -e "${CYAN}Enter the username for the mail server database: ${NC}" read mailuser echo -e "${CYAN}Enter the password for $mailuser: ${NC}" read mailpass echo -e "${CYAN}Enter the password for the mail box admin@$domain: ${NC}" read adminpassword #CertBot get the wildcard certificate echo -e "${CYAN}Setting up Certbot${NC}" certbot certonly --manual --domain "$domain" --domain "*.$domain" --server https://acme-v02.api.letsencrypt.org/directory echo -e "${GREEN}Done.${NC}" #Setup Apache2 echo -e "${CYAN}Setting up Apache config${NC}" cat > "/var/www/$domain/index.html" <<EOF <!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>$domain</title> <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css"> <style> html, body {background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0;} .full-height {height: 100vh;} .flex-center {align-items: center; display: flex; justify-content: center;} .position-ref {position: relative;} .top-right {position: absolute; right: 10px; top: 18px;} .content {text-align: center;} .title {font-size: 84px;} .links > a {color: #636b6f;padding: 0 25px;font-size: 12px;font-weight: 600;letter-spacing: .1rem;text-decoration: none;text-transform: uppercase;} .m-b-md {margin-bottom: 30px;} </style> </head> <body> <div class="flex-center position-ref full-height"> <div class="content"> <div class="title m-b-md">$domain</div> </div> </div> </body> </html> EOF cat > "/etc/apache2/sites-available/000-default.conf" <<EOF <VirtualHost *:80> DocumentRoot "/var/www/$domain" ErrorLog \${APACHE_LOG_DIR}/error.log CustomLog \${APACHE_LOG_DIR}/access.log combined ServerAdmin webmaster@$domain <Directory "/var/www/$domain"> AllowOverride All allow from all Options +Indexes </Directory> RewriteEngine on RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] </VirtualHost> EOF cat > "/etc/apache2/sites-available/000-default-le-ssl.conf" <<EOF <IfModule mod_ssl.c> <VirtualHost *:443> DocumentRoot "/var/www/$domain" <Directory "/var/www/$domain"> AllowOverride All allow from all Options +Indexes </Directory> SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf Header always set Strict-Transport-Security "max-age=31536000" </VirtualHost> </IfModule> EOF cat > "/etc/letsencrypt/options-ssl-apache.conf" <<EOF # This file contains important security parameters. If you modify this file # manually, Certbot will be unable to automatically provide future security # updates. Instead, Certbot will print and log an error message with a path to # the up-to-date file that you will need to refer to when manually updating # this file. SSLEngine on # Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS SSLHonorCipherOrder on SSLCompression off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common #CustomLog /var/log/apache2/access.log vhost_combined #LogLevel warn #ErrorLog /var/log/apache2/error.log # Always ensure Cookies have "Secure" set (JAH 2012/1) #Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "\$1; Secure\$3\$4" EOF echo -e "${GREEN}Done.${NC}" #Restart Apache2 echo -e "${CYAN}Restarting Apache${NC}" a2ensite 000-default-le-ssl chown -R www-data:www-data /var/www service apache2 restart rm -rf /var/www/html echo -e "${GREEN}Done.${NC}" #Configure Postfix echo -e "${CYAN}Configuring Postfix${NC}" cat > "/etc/postfix/main.cf" <<EOF smtpd_banner = $domain ESMTP biff = no append_dot_mydomain = no readme_directory = no smtpd_tls_cert_file = /etc/letsencrypt/live/$domain/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/$domain/privkey.pem smtpd_use_tls = yes smtpd_tls_session_cache_database = btree:\${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:\${data_directory}/smtp_scache smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination myhostname = $domain alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = /etc/mailname mydestination = localhost relayhost = mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all inet_protocols = all smtpd_tls_auth_only = yes smtp_tls_security_level = may smtpd_tls_security_level = may smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-virtual-email2email.cf milter_protocol = 2 milter_default_action = accept smtpd_milters = inet:localhost:12301 non_smtpd_milters = inet:localhost:12301 EOF cat > "/etc/postfix/master.cf" <<EOF smtp inet n - y - - smtpd submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=no -o milter_macro_daemon_name=ORIGINATING smtps inet n - y - - smtpd -o syslog_name=postfix/smtps -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=no -o milter_macro_daemon_name=ORIGINATING pickup unix n - y 60 1 pickup cleanup unix n - y - 0 cleanup qmgr unix n - n 300 1 qmgr tlsmgr unix - - y 1000? 1 tlsmgr rewrite unix - - y - - trivial-rewrite bounce unix - - y - 0 bounce defer unix - - y - 0 bounce trace unix - - y - 0 bounce verify unix - - y - 1 verify flush unix n - y 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - y - - smtp relay unix - - y - - smtp showq unix n - y - - showq error unix - - y - - error retry unix - - y - - error discard unix - - y - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - y - - lmtp anvil unix - - y - 1 anvil scache unix - - y - 1 scache maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d \${recipient} uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a\$sender - \$nexthop!rmail (\$recipient) ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r \$nexthop (\$recipient) bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t\$nexthop -f\$sender \$recipient scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store \${nexthop} \${user} \${extension} mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py \${nexthop} \${user} EOF cat > "/etc/postfix/mysql-virtual-mailbox-domains.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT 1 FROM virtual_domains WHERE name='%s' EOF cat > "/etc/postfix/mysql-virtual-alias-maps.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT destination FROM virtual_aliases WHERE source='%s' EOF cat > "/etc/postfix/mysql-virtual-mailbox-maps.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT 1 FROM virtual_users WHERE email='%s' EOF cat > "/etc/postfix/mysql-virtual-email2email.cf" <<EOF user = $mailuser password = $mailpass hosts = 127.0.0.1 dbname = $maildatabase query = SELECT email FROM virtual_users WHERE email='%s' EOF echo -e "${GREEN}Done.${NC}" #Configure MySQL echo -e "${CYAN}Configuring MySQL${NC}" cat > "/root/email_mysql.sql" <<EOF DROP DATABASE IF EXISTS $maildatabase; CREATE DATABASE $maildatabase; USE $maildatabase; GRANT ALL ON $maildatabase.* TO '$mailuser'@'localhost' IDENTIFIED BY '$mailpass'; FLUSH PRIVILEGES; CREATE TABLE `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `password` varchar(106) NOT NULL, `email` varchar(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `destination_id` int(11) NULL, `source` varchar(100) NOT NULL, `destination` varchar(100) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE, FOREIGN KEY (destination_id) REFERENCES virtual_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `$maildatabase`.`virtual_domains` (`id` ,`name`) VALUES ('1', '$domain'); INSERT INTO `$maildatabase`.`virtual_users` (`id`, `domain_id`, `password` , `email`) VALUES ('1', '1', ENCRYPT('$adminpassword', CONCAT('\$6$', SUBSTRING(SHA(RAND()), -16))), 'admin@$domain'); INSERT INTO `$maildatabase`.`virtual_aliases` (`id`, `domain_id`, `destination_id`, `source`, `destination`) VALUES ('1', '1', '1', '@$domain', 'admin@$domain'); EOF mysql -u root -p < "/root/email_mysql.sql" echo -e "${GREEN}Done.${NC}" #Configure Dovecot echo -e "${CYAN}Configuring Dovecot${NC}" mkdir -p "/var/mail/vhosts/$domain" groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/mail chown -R vmail:vmail /var/mail cat > "/etc/dovecot/dovecot.conf" <<EOF !include_try /usr/share/dovecot/protocols.d/*.protocol protocols = imap pop3 lmtp !include conf.d/*.conf !include_try local.conf EOF cat > "/etc/dovecot/conf.d/10-mail.conf" <<EOF mail_location = maildir:/var/mail/vhosts/%d/%n namespace inbox { inbox = yes } mail_privileged_group = mail EOF cat > "/etc/dovecot/conf.d/10-auth.conf" <<EOF disable_plaintext_auth = yes auth_mechanisms = plain login !include auth-sql.conf.ext EOF cat > "/etc/dovecot/conf.d/auth-sql.conf.ext" <<EOF passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = static args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n } EOF cat > "/etc/dovecot/dovecot-sql.conf.ext" <<EOF driver = mysql connect = host=127.0.0.1 dbname=$maildatabase user=$mailuser password=$mailpass default_pass_scheme = SHA512-CRYPT password_query = SELECT email as user, password FROM virtual_users WHERE email='%u'; EOF cat > "/etc/dovecot/conf.d/10-master.conf" <<EOF service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 ssl = yes } } service pop3-login { inet_listener pop3 { port = 0 } inet_listener pop3s { port = 995 ssl = yes } } service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } } service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } unix_listener auth-userdb { mode = 0600 user = vmail } user = dovecot } service auth-worker { user = vmail } EOF cat > "/etc/dovecot/conf.d/10-ssl.conf" <<EOF ssl = required ssl_cert = <//etc/letsencrypt/live/$domain/fullchain.pem ssl_key = </etc/letsencrypt/live/$domain/privkey.pem EOF chown -R vmail:dovecot /etc/dovecot service dovecot restart echo -e "${GREEN}Done.${NC}" #Configure DKIM echo -e "${CYAN}Configuring DKIM${NC}" mkdir /etc/opendkim mkdir /etc/opendkim/keys mkdir /etc/opendkim/keys/$domain cat > "/etc/opendkim.conf" <<EOF Syslog yes Domain * Selector mail AutoRestart Yes Background yes Canonicalization relaxed/simple DNSTimeout 5 Mode sv SignatureAlgorithm rsa-sha256 Statistics /var/log/dkim-filter/dkim-stats UMask 002 AutoRestartRate 10/1h SyslogSuccess Yes LogWhy Yes ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable PidFile /var/run/opendkim/opendkim.pid Socket inet:12301@localhost EOF cat > "/etc/default/opendkim" <<EOF SOCKET="local:/var/run/opendkim/opendkim.sock" SOCKET="inet:12301@localhost" EOF cat > "/etc/opendkim/TrustedHosts" <<EOF 127.0.0.1 localhost $domain *.$domain EOF cat > "/etc/opendkim/KeyTable" <<EOF mail._domainkey.$domain $domain:mail:/etc/opendkim/keys/$domain/mail.private EOF cat > "/etc/opendkim/SigningTable" <<EOF *@$domain mail._domainkey.$domain EOF opendkim-genkey -s mail -d $domain -D /etc/opendkim/keys/$domain chown opendkim:opendkim /etc/opendkim/keys/$domain/mail.private mkdir /var/log/dkim-filter touch /var/log/dkim-filter/dkim-stats chown -R opendkim:opendkim /var/log/dkim-filter service postfix restart service opendkim restart echo -e "${GREEN}Done.${NC}" echo -e "${CYAN}The installation script has finished.${NC}" echo -e "${RED}PLEASE REBOOT THIS SERVER.${NC}" |
The repository for this post can be found on GitLab here .
The repository for this post can be found on Lupe Code’s GitLab mirror here .