Arch Post-Installation Checklist
Passwords & User Creation
Make sure root
has a password.
Make sure you have a primary user set up.
# useradd -m -u <id -ge 1000> -g users -G wheel,games,video,audio,optical,storage,scanner,power <user> # passwd <user>
/etc/fstab
Time Zone
# ln -sf /usr/share/zoneinfo/<region>/<city> /etc/localtime # hwclock --systohc
Localization
Un-comment your desired locales in /etc/locale.conf
, then run
locale-gen
If you don't have the default /etc/locale.gen
file:
# rm /etc/locale.gen # pacman -Syu glibc
Edit /etc/locale.conf
as you see fit
/etc/locale.conf
LANG=en_US.UTF-8 LANGUAGE=en_US LC_COLLATE=POSIX LC_MESSAGES=C LC_CTYPE=en_US.UTF-8 LC_NUMERIC=en_US.UTF-8 LC_TIME=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=en_US.UTF-8 LC_ADDRESS=en_US.UTF-8 LC_TELEPHONE=en_US.UTF-8 LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=en_US.UTF-8
Set up /etc/vconsole.conf
with a keymap and (optionally) a font:
/etc/vconsole.conf
KEYMAP=us FONT=Lat2-Terminus16
Initramfs
Look for and edit the following lines:
/etc/mkinitcpio.conf
MODULES=([amdgpu|bochs_drm|cirrus|i915|nouveau|(nvidia nvidia_modeset nvidia_uvm nvidia_drm)] [ehci_pci usb_storage]>) HOOKS=(base udev autodetect modconf block [zfs] filesystems keyboard fsck [encrypt] keymap consolefont) COMPRESSION=lz4
Networking
Host Name
Make sure a host name is set in /etc/hostname
Then edit /etc/hosts
/etc/hosts
127.0.0.1 localhost.localdomain locahost ::1 localhost.localdomain localhost 127.0.1.1 <hostname>.localdomain <hostname>
Static Addressing
Use systemd-networkd
when a machine will use a static address without consulting a DHCP server.
IPv4 Only
/etc/systemd/network/network.network
[Match] MACAddress=<mac-address> [Network] Address=<ipv4-address>/<mask> DNS=<ipv4-address> Gateway=<ipv4-address> LinkLocalAddressing=no IPv6AcceptRA=no
IPv4 & IPv6
/etc/systemd/network/network.network
[Match] MACAddress=<mac-address> [Network] Address=<ipv6-address>/<mask> DNS=<ipv6-address> Gateway=<ipv6-address> Address=<ipv4-address>/<mask> DNS=<ipv4-address> Gateway=<ipv4-address>
Dynamic Addressing
It's preferable to use connman
or Network Manager
for dynamic addresses as systemd-networkd
doesn't play well with interfaces coming and going.
If you'd rather use systemd-networkd
for DHCP:
/etc/systemd/network/network.network
[Match] MACAddress=<mac-address> [Network] DHCP=yes [DHCP] UseMTU=true
IPTables Firewall
/etc/iptables/iptables.rules
# SIMPLE STATEFUL FIREWALL *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [100308:88697975] :TCP - [0:0] :UDP - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # OPEN NECESSARY PORTS HERE -A TCP -p tcp -m tcp --dport 22 -j ACCEPT -m comment --comment "ssh" -A TCP -p tcp -m tcp --dport 80 -j ACCEPT -m comment --comment "http" -A TCP -p tcp -m tcp --dport 443 -j ACCEPT -m comment --comment "https" -A TCP -p tcp -m tcp --dport 465 -j ACCEPT -m comment --comment "smtps" -A TCP -p tcp -m tcp --dport 587 -j ACCEPT -m comment --comment "starttls" -A TCP -p tcp -m tcp --dport 873 -j ACCEPT -m comment --comment "rsync" -A TCP -p tcp -m tcp --dport 993 -j ACCEPT -m comment --comment "imaps" -A TCP -p tcp -m tcp --dport 64738 -j ACCEPT -m comment --comment "mumble tcp" -A UDP -p udp -m udp --dport 64738 -j ACCEPT -m comment --comment "mumble udp" COMMIT
Pacman
Mirror List
Install and use reflector
to automate the use and selection of mirrors.
# pacman -Syu reflector # reflector -c <country> -p https -l 5 --sort rate --save /etc/pacman.d/mirrorlist
General Utilities
# pacman -Syu --needed fail2ban git rsync openssh pkgfile vim
# pacman -Syu --needed dovecot postfix redis rspamd swaks
Nginx Web Server and Reverse Proxy
# pacman -Syu --needed ca-certificates certbot-nginx mariadb nginx php-fpm
Roundcube Web Mail
# pacman -Syu --needed pigeonhole roundcube
Fail2Ban
/etc/fail2ban/jail.local
[DEFAULT] bantime = 1d destemail = root@bwt.com.de sender = fail2ban@bwt.com.de action = %(action_mwl)s
/etc/fail2ban/jail.d/sshd.local
[sshd] enabled = true filter = sshd banaction = iptables backend = systemd maxretry = 5 findtime = 1d bantime = 2w ignoreip = 127.0.0.1/8
/etc/fail2ban/jail.d/postfix-ispmail.local
[postfix-ispmail] enabled = true filter = postfix port = smtp,submission banaction = iptables backend = systemd maxretry = 5 findtime = 1d bantime = 2w ignoreip = 192.99.246.231/32
/etc/fail2ban/filter.d/postfix-ispmail.conf
[INCLUDES] before = common.conf [Definition] _daemon = postfix(-\w+)?/(?:submission/|smtps/)?smtp[ds] failregex = ^%(__prefix_line)slost connection after AUTH from \S+\[<HOST>\]$ ignoreregex = [Init] journalmatch = _SYSTEMD_UNIT=postfix.service
SSH Setup
Look for and edit the following lines in /etc/ssh/sshd_config
:
/etc/ssh/ssd_config
Port <port> AddressFamily <any|inet|inet6> ListenAddress <ip4-address> ListenAddress <ip6-address> LogLevel VERBOSE PermitRootLogin prohibit-password PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no UsePAM yes AllowUsers <space-separated-list-of-users> AllowAgentForwarding no AllowTcpForwarding no
Then make sure the sshd
service is enabled and running:
# systemctl enable --now sshd
MariaDB
Data Directory
If you want to put your databases somewhere other than the default /var/lib/mysql
:
# mkdir <dir> # chown -R mysql:mysql <dir>
tmpfs for tmpdir
The directory used by MariaDB for storing temporary files is named tmpdir. For example, it is used to perform disk based large sorts, as well as for internal and explicit temporary tables.
Create the directory with appropriate permissions:
# mkdir -pv <dir> # chown mysql:mysql <dir>
Find the id and gid of the mysql user and group:
$ id mysql
uid=27(mysql) gid=27(mysql) groups=27(mysql)
Add to your /etc/fstab file.
/etc/fstab
# Static information about the filesystems. # See fstab(5) for details. # <file system> <dir> <type> <options> <dump> <pass> ... tmpfs /srv/sqltmp tmpfs rw,noatime,gid=933,uid=993,size=100M,mode=0750 0 0 ...
Configuration File
/etc/my.cnf.d/server.cnf
... [mysqld] ... datadir=<dir> skip-networking tmpdir=<dir> ...
Initial Setup
# mariadb-install-db --user=mysql --basedir=/usr --datadir=<dir></nowiki>
Start the Server
# systemctl enable --now mariadb
Security Settings
# mysql_secure_installation
Create a user:
$ mysql -u root -p
MariaDB> CREATE USER '<user>'@'localhost' IDENTIFIED BY '<password>'; MariaDB> GRANT ALL PRIVILEGES ON mydb.* TO '<password>'@'localhost'; MariaDB> FLUSH PRIVILEGES; MariaDB> quit
Postfix
Create MariaDB Databases for Postfix
MariaDB [(none)]> CREATE DATABASE MAIL; MariaDB [(none)]> CREATE USER 'mailuser'@'127.0.0.1' IDENTIFIED BY '<password>'; MariaDB [(none)]> CREATE USER 'mailadmin'@'localhost' IDENTIFIED BY '<password>'; MariaDB [(none)]> GRANT ALL ON MAIL.* TO 'mailadmin'@'localhost'; MariaDB [(none)]> GRANT SELECT ON MAIL.* TO 'mailuser'@'127.0.0.1';
MariaDB [(none)]> USE MAIL; MariaDB [(MAIL)]> CREATE TABLE IF NOT EXISTS `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
MariaDB [(none)]> USE MAIL; MariaDB [(MAIL)]> CREATE TABLE IF NOT EXISTS `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `email` varchar(100) NOT NULL, `password` varchar(150) 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;
USE MAIL; MariaDB [(MAIL)]> CREATE TABLE IF NOT EXISTS `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT 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 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Configure Postfix to Use MariaDB
/etc/postfix/mysql-virtual-mailbox-domains.cf
user = mailuser password = <password> hosts = localhost dbname = MAIL query = SELECT 1 FROM virtual_domains WHERE name='%s'
/etc/postfix/mysql-virtual-mailbox-maps.cf
user = mailuser password = <password> hosts = 127.0.0.1 dbname = MAIL query = SELECT 1 FROM virtual_users WHERE email='%s'
/etc/postfix/mysql-virtual-alias-maps.cf
user = mailuser password = <password> hosts = 127.0.0.1 dbname = MAIL query = SELECT destination FROM virtual_aliases WHERE source='%s'
/etc/postfix/mysql-email2email.cf
user = mailuser password = <password> hosts = 127.0.0.1 dbname = MAIL query = SELECT email FROM virtual_users WHERE email='%s'
# postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf # postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf # postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf # chgrp postfix /etc/postfix/mysql-*.cf # chmod 640 /etc/postfix/mysql-*.cf
Dovecot
# groupadd -g 5000 vmail # useradd -g vmail -u 5000 vmail -d /var/vmail -m # chown -R vmail:vmail /srv/mail
# cp /usr/share/doc/dovecot/example-config/dovecot.conf /etc/dovecot # cp -r /usr/share/doc/dovecot/example-config/conf.d /etc/dovecot
/etc/dovecot/conf.d/10-auth.conf
... #!include auth-system.conf.ext !include auth-sql.conf.ext ...
/etc/dovecot/conf.d/auth-sql.conf.ext
... #userdb { # driver = sql # args = /etc/dovecot/dovecot-sql.conf.ext #} ... userdb { driver = static args = uid=vmail gid=vmail home=/srv/mail/%d/%n }
/etc/dovecot/conf.d/10-mail.conf
... mail_location = maildir:/srv/mail/%d/%n/Maildir ... namespace inbox { ... separator = . ... } ...
/etc/dovecot/conf.d/10-master.conf
... service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix } ... } ... service auth { ... # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } ... } ...
/etc/dovecot/conf.d/10-ssl.conf
... ssl = yes ... ssl_cert = </etc/letsencrypt/live/<domain>/fullchain.pem ssl_key = </etc/letsencrypt/live/<domain>/privkey.pem ... ssl_ca = </etc/letsencrypt/live/<domain>/chain.pem ...
/etc/dovecot/conf.d/15-mailboxes.conf
... mailbox INBOX.Drafts { special_use = \Drafts auto = subscribe } mailbox INBOX.Junk { special_use = \Junk auto = subscribe autoexpunge = 30d } mailbox INBOX.Trash { special_use = \Trash auto = subscribe autoexpunge = 30d } mailbox INBOX.Sent { special_use = \Sent auto = subscribe } ...
/etc/dovecot/conf.d/20-imap.conf
... protocol imap { # Space separated list of plugins to load (default is global mail_plugins). mail_plugins = $mail_plugins imap_sieve ... }
/etc/dovecot/conf.d/20-lmtp.conf
... protocol lmtp { # Space separated list of plugins to load (default is global mail_plugins). mail_plugins = $mail_plugins sieve ... }
/etc/dovecot/conf.d/90-sieve.conf
... sieve_after = /etc/dovecot/sieve-after ... sieve_plugins = sieve_imapsieve sieve_extprograms ... # From elsewhere to Junk folder imapsieve_mailbox1_name = Junk imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_before = file:/etc/dovecot/sieve/learn-spam.sieve # From Junk folder to elsewhere imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Junk imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/etc/dovecot/sieve/learn-ham.sieve sieve_pipe_bin_dir = /etc/dovecot/sieve sieve_global_extensions = +vnd.dovecot.pipe }
# mkdir /etc/dovecot/sieve-after
/etc/dovecot/sieve-after/spam-to-folder.sieve
require ["fileinto","mailbox"]; if header :contains "X-Spam" "Yes" { fileinto :create "INBOX.Junk"; stop; }
# mkdir /etc/dovecot/sieve
/etc/dovecot/sieve/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamd-learn-spam.sh";
/etc/dovecot/sieve/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamd-learn-ham.sh";
/etc/dovecot/dovecot-sql.conf.ext
driver = mysql connect = host=127.0.0.1 dbname=MAIL user=mailuser password=<password> default_pass_scheme = SHA256-CRYPT password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
/etc/dovecot/sieve/rspamd-learn-spam.sh
#!/usr/bin/env sh exec /usr/bin/rspamc learn_spam
/etc/dovecot/sieve/rspamd-learn-ham.sh
#!/usr/bin/env sh exec /usr/bin/rspamc learn_ham
# sievec /etc/dovecot/sieve-after/spam-to-folder.sieve # sievec /etc/dovecot/sieve/learn-spam.sieve # sievec /etc/dovecot/sieve/learn-ham.sieve # chown root:root /etc/dovecot/dovecot-sql.conf.ext # chmod 600 /etc/dovecot/dovecot-sql.conf.ext # chmod 600 /etc/dovecot/sieve/learn-{spam,ham}.sieve # chmod 700 /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh # chown vmail:vmail /etc/dovecot/sieve/learn-{spam,ham}.sieve # chown vmail:vmail /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh
Final Postfix Configuration
# postconf virtual_transport=lmtp:unix:private/dovecot-lmtp # postconf smtpd_sasl_type=dovecot # postconf smtpd_sasl_path=private/auth # postconf smtpd_sasl_auth_enable=yes # postconf smtpd_tls_security_level=may # postconf smtpd_tls_auth_only=yes # postconf smtpd_tls_cert_file=/etc/letsencrypt/live/<domain>/fullchain.pem # postconf smtpd_tls_key_file=/etc/letsencrypt/live/<domain>/privkey.pem # postconf smtp_tls_security_level=may # postconf smtpd_milters=inet:127.0.0.1:11332 # postconf non_smtpd_milters=inet:127.0.0.1:11332 # postconf milter_protocol=6 # postconf milter_mail_macros="i {mail_addr} {client_addr} {client_name} {auth_authen}"
/etc/postfix/master.cf
... submission inet n - - - - 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_sasl_security_options=noanonymous -o smtpd_sender_login_maps=mysql:/etc/postfix/mysql-email2email.cf -o smtpd_sender_restrictions=reject_sender_login_mismatch -o smtpd_sasl_local_domain=$myhostname -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject ...
Rspamd
# mkdir /etc/rspamd/conf.d
/etc/rspamd/override.d/milter_headers.conf
extended_spam_headers = true;
/etc/rspamd/override.d/classifier-bayes.conf
autolearn = true;
PHP-FPM
Look for and edit the following lines in /etc/php/php.ini
:
/etc/php/php.ini
[PHP] open_basedir = /srv/http/:/home/:/tmp/:/usr/share/pear/:/usr/share/webapps/:/dev/urandom:/proc/meminfo include_path = ".:/php/includes:/usr/share/pear" upload_max_filesize = 8M extension=apcu extension=dba extension=exif extension=gd extension=gettext extension=iconv extension=intl extension=sodium extension=ldap extension=mysqli zend_extension=opcache extension=pdo_mysql extension=soap [Pdo_mysql] pdo_mysql.cache_size = 2000 [Session] session.save_path = "/tmp/php/sessions" [opcache] opcache.enable=1 opcache.enable_cli=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000 opcache.revalidate_freq=1 opcache.save_comments=1
Then make sure the php-fpm
service is enabled and running:
# systemctl enable --now php-fpm
Nginx
Main Configuration
First, edit /etc/nginx/nginx.conf
:
/etc/nginx/nginx.conf
user http; worker_processes 1; # one(1) worker or equal the number of _real_ cpu cores. 4=4 core cpu worker_priority 15; # renice workers to reduce priority compared to system processes for machine health. Worst case nginx will get ~25% system resources at nice=15 worker_rlimit_nofile 1024; # maximum number of open files worker_cpu_affinity auto; events { multi_accept on; accept_mutex on; # serially accept() connections and pass to workers, efficient if workers gt 1 accept_mutex_delay 500ms; # worker process will accept mutex after this delay if not assigned. (default 500ms) worker_connections 1024; # number of parallel or concurrent connections per worker_processes } http { charset utf-8; aio on; # asynchronous file I/O, fast with ZFS, make sure sendfile=off sendfile off; # on for decent direct disk IO, off for VMs tcp_nopush off; # turning on requires sendfile=on tcp_nodelay on; # Nagle buffering algorithm, used for keepalive only server_tokens off; # version number in error pages log_not_found off; types_hash_max_size 4096; # MIME include mime.types; default_type application/octet-stream; # logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # SSL ssl_session_timeout 1440m; ssl_session_cache shared:le_nginx_SSL:10m; ssl_session_tickets off; ssl_prefer_server_ciphers off; # Diffie-Hellman parameter for DHE ciphersuites ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Mozilla Intermediate configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s; resolver_timeout 2s; # Size Limits #client_body_buffer_size 8k; #client_header_buffer_size 1k; client_max_body_size 16M; #large_client_header_buffers 4 4k/8k; ## From StackOverflow: for "upstream sent too big header while reading response header from upstream" fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; # Timeouts, do not keep connections open longer then necessary to reduce # resource usage and deny Slowloris type attacks. client_body_timeout 5s; # maximum time between packets the client can pause when sending nginx any data client_header_timeout 5s; # maximum time the client has to send the entire header to nginx keepalive_timeout 75s; # timeout which a single keep-alive client connection will stay open send_timeout 15s; # maximum time between packets nginx is allowed to pause when sending the client data ## General Options gzip off; # disable on the fly gzip compression due to higher latency, only use gzip_static #gzip_http_version 1.0; # serve gzipped content to all clients including HTTP/1.0 gzip_static on; # precompress content (gzip -9) with an external script #gzip_vary on; # send response header "Vary: Accept-Encoding" gzip_proxied any; # allows compressed responses for any request even from proxies ignore_invalid_headers on; keepalive_requests 50; # number of requests per connection, does not affect SPDY keepalive_disable none; # allow all browsers to use keepalive connections max_ranges 1; # allow a single range header for resumed downloads and to stop large range header DoS attacks msie_padding off; open_file_cache max=1000 inactive=2h; open_file_cache_errors on; open_file_cache_min_uses 1; open_file_cache_valid 1h; output_buffers 1 512; postpone_output 1440; # postpone sends to match our machine's MSS read_ahead 512K; # kernel read head set to the output_buffers recursive_error_pages on; reset_timedout_connection on; # reset timed out connections freeing ram server_name_in_redirect off; # if off, nginx will use the requested Host header source_charset utf-8; # same value as "charset" ## Request limits limit_req_zone $binary_remote_addr zone=gulag:1m rate=60r/m; ## Log Format log_format main '$remote_addr $host $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $ssl_cipher $request_time'; # load configs include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*.conf; }
Make the sites-available
and sites-enabled
directories.
# mkdir /etc/nginx/sites-{available,enabled}
Non-Proxied Web Site
Make a test site available by creating /etc/nginx/sites-available/<domain>.conf
:
(Remove the #
after setting up Let's Encrypt.)
/etc/nginx/sites-available/<domain>.conf
server { listen 80; listen [::]:80; server_name <domain>; root /srv/http/$host; index index.html index.php; # if ($host = <domain>) { # return 301 https://$host$request_uri; # } # # return 404; # #} # #server { # # listen 443 ssl http2; # listen [::]:443 ssl http2; # server_name <domain>; # root /srv/http/$host; # index index.html index.php; # # ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem; # ssl_trusted_certificate /etc/letsencrypt/live/<domain>/chain.pem; # # fastcgi_param HTTPS on; # # add_header Strict-Transport-Security max-age=15768000; add_header Cache-Control "public"; add_header X-Frame-Options "DENY"; access_log /var/log/nginx/access.log main buffer=32k; error_log /var/log/nginx/error.log error; limit_req zone=gulag burst=200 nodelay; # ACME challenge location ^~ /.well-known { allow all; alias /var/lib/letsencrypt/$host/.well-known; default_type "text/plain"; try_files $uri =404; } location ~ /(data|conf|bin|inc)/ { deny all; } # static file 404's are strict access by hostname aren't logged and expires header is set to maximum age location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ { access_log off; expires max; } location ~ \.php$ { try_files $uri = 404; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } location ~ \.php5$ { try_files $uri = 404; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php5; include fastcgi.conf; } location ~ /\.ht { deny all; } }
Enable the site
# ln -s ../sites-available/<domain>.conf /etc/nginx/sites-enabled/<domain>.conf
Then create index.php
for your new site.
/srv/http/<domain>/index.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Server Configuration Confirmation</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body style="font-family:sans-serif;"> <h1>Web server is properly configured!</h1> <?php echo "<h2>PHP is properly configured as well!</h2>" ?> <p>Time to add some content!</p> </body> </html>
Finally, make sure the nginx
service is enabled and running:
# systemctl enable --now nginx
Let's Encrypt
# certbot --nginx
The nginx
plugin will guide you and help automate the process.
Take note that the nginx
configuration in this guide takes into account the settings suggested by certbot
.
Automatic Renewal
These will automatically renew your certificates every 2 months on the first Sunday of the month at 4am.
Systemd
/etc/systemd/system/certbot.service
[Unit] Description=Let's Encrypt renewal [Service] Type=oneshot ExecStart=/usr/bin/certbot renew --agree-tos --no-redirect
/etc/systemd/system/certbot.timer
[Unit] Description=Bi-monthly renewal of Let's Encrypt's certificates [Timer] OnCalendar=Sun *-1,3,5,7,9,11-1..7 04:00:00 RandomizedDelaySec=1h Persistent=true [Install] WantedBy=timers.target
Crontab
0 4 1-7 2-12/2 0 /usr/bin/certbot renew --agree-tos --no-redirect
ISPmail Admin
Create a config like Arch_Post-Installation_Checklist#Non-Proxied_Web_Site
Then, in the site's root:
# wget 'https://www.ima.jungclaussen.com/dwn/dwn.php?v=0.9.6&f=.tar.gz' # tar -xvf 'dwn.php?v=0.9.6&f=.tar.gz' # mv ispmail*/htdocs/* ./ # rm -r 'dwn.php?v=0.9.6&f=.tar.gz' ispmail*
Then edit the configuration file:
<ispmail_root>/cfg/config.inc.php
<?php // @package ISPmail_Admin // @author Ole Jungclaussen // @version 0.9.0 // SHOW PHP ERRORS (DEBUGGING) // ini_set('display_startup_errors', 1); // ini_set('display_errors', 1); // error_reporting(-1); // DATABASE ACCESS define('IMA_CFG_DB_HOST', '127.0.0.1'); define('IMA_CFG_DB_PORT', '3306'); define('IMA_CFG_DB_USER', 'mailadmin'); define('IMA_CFG_DB_PASSWORD', '<password>'); define('IMA_CFG_DB_DATABASE', 'MAIL'); // PASSWORD HASHES (enable only *one*) define('IMA_CFG_USE_SHA256_HASHES', true); // define('IMA_CFG_USE_MD5_HASHES', true); // ACCESS CONTROL: uncomment the type you want to use. define('IMA_CFG_LOGIN', IMA_LOGINTYPE_ACCOUNT); // define('IMA_CFG_LOGIN', IMA_LOGINTYPE_ADM); // define('IMA_CFG_LOGIN', IMA_LOGINTYPE_ADMAUTO); // ADMINISTRATOR'S NAME AND PASSWORD define('IMA_CFG_ADM_USER', 'admin'); // admin username define('IMA_CFG_ADM_PASS', '<password>'); // admin password // LISTS // Spread long lists on multiple pages. Set number of maximum entries // per page. Changes take effect after login/logout. If not defined, // defaults to 65535. // define('IMA_LIST_MAX_ENTRIES', 200); ?>
You should now be able to log in and set up your virtual mailboxes.