diff --git a/bin/deploy/install.yml b/bin/deploy/install.yml new file mode 100644 index 0000000000000000000000000000000000000000..3b24fd59448ce9382761503f2b70ef7369036e93 --- /dev/null +++ b/bin/deploy/install.yml @@ -0,0 +1,306 @@ +# Ansible playbook for basic web server configuration. +# +# Run with: +# ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook deploy/install.yml -i deploy/inventory.ini --verbose + +# Notes: +# +# /etc/apache2 uses OS defaults aside from "site-available", "sites-enabled" and +# "conservancy.conf". +# +# Current site does not use "django.contrib.staticfiles", so no need to run +# `collectstatic`. +# +# SQLite database lives at /var/lib/www/database. +# +# Disabled Rackspace CDN videos. + + - name: Configure web server + hosts: web + become: true + vars: + ansible_ssh_pipelining: true + tasks: + - name: Install unattended upgrades + apt: + name: unattended-upgrades + + - name: Configure unattended upgrades overrides + # See defaults in 50unattended-upgrades. + copy: + dest: /etc/apt/apt.conf.d/20auto-upgrades + content: | + APT::Periodic::Update-Package-Lists "1"; + APT::Periodic::Unattended-Upgrade "1"; + Unattended-Upgrade::Automatic-Reboot "true"; + Unattended-Upgrade::Automatic-Reboot-Time "02:00"; + Unattended-Upgrade::Mail "root"; + + - name: Add extensive history logging + blockinfile: + path: /etc/bash.bashrc + block: | + # Write to history file immediately (rather than only when shell is + # closed). For setting history length see HISTSIZE and HISTFILESIZE in + # bash(1). + shopt -s histappend + PROMPT_COMMAND='history -a' + HISTSIZE=1000000 + HISTFILESIZE=1000000 + insertafter: EOF + + - name: Mount the media volume + # OSUOSL VMs come with fixed storage that's tied to the cores and RAM + # selection. Easier to put this data on an external volume. + ansible.posix.mount: + src: /dev/sdb1 + path: /var/www/media + fstype: ext4 + state: mounted + boot: false + + - name: Install Apache + apt: + name: apache2,libapache2-mod-wsgi-py3 + + - apache2_module: + state: present + name: ssl + + - apache2_module: + state: present + name: rewrite + + # The proxy and proxy-http modules are required to rewrite /.well-known/ + # requests to the mail server if the file doesn't exist. This is use to + # renew Let's Encrypt certificates. + - apache2_module: + state: present + name: proxy + + - apache2_module: + state: present + name: proxy-http + + - name: Install Postfix + apt: + pkg: + - postfix + # libsasl2-modules fixes "SASL authentication failure: No worthy mechs found" + - libsasl2-modules + - mailutils + + # # Commented because you only want this on first run ever. + # - name: Add file for SMTP credentials + # copy: + # dest: /etc/postfix/sasl_passwd + # content: |- + # # After updating, run `sudo postmap hash:/etc/postfix/sasl_passwd`. + # [mail.sfconservancy.org]:587 conference@sfconservancy.org:PASSWORD + + - name: Configure Postfix for relaying + copy: + src: postfix/main.cf + dest: /etc/postfix/main.cf + notify: + - restart postfix + + - name: Alias mail to root + copy: + dest: /etc/aliases + content: |- + postmaster: root + root: sysadmin@sfconservancy.org, sysadmin@sturm.com.au + notify: + - restart postfix + + - name: Install Certbot + apt: + name: certbot, python3-certbot-apache + + - name: Install Python dependencies + apt: + name: python3-django,python3-bs4,python3-html5lib,python3-django-countries + + - name: Install Python essentials + apt: + name: python3-venv,python3-pip,python3-wheel + + - name: Install Python build dependencies + apt: + name: build-essential,python3-dev,libffi-dev + + - name: Security settings + apt: + name: fail2ban + + - name: Disable SSH password authentication + lineinfile: + path: /etc/ssh/sshd_config + line: 'PasswordAuthentication no' + regexp: 'PasswordAuthentication ' + notify: + - restart sshd + + - name: Install utilities + apt: + name: tmux,curl,git,magic-wormhole,htop,rsync + + - name: Create the project directory + file: + path: /var/www/website + state: directory + owner: www-data + group: www-data + mode: '0755' + + # TODO: Needs to force owner to www-data:www-data + - name: Git checkout + ansible.builtin.git: + repo: 'https://k.sfconservancy.org/website' + dest: /var/www/website + version: master + remote: upstream + + - name: Create the database directory + file: + path: /var/lib/www/database + state: directory + owner: www-data + group: www-data + mode: '0755' + + - name: Create static dir + file: + path: /var/www/website/conservancy/static + state: directory + owner: www-data + group: www-data + mode: '0755' + + - name: Install `netfilter-persistent` && `iptables-persistent` packages + apt: + pkg: + - iptables-persistent + - netfilter-persistent + + - name: Install iptables # May need kernel reload/reboot + apt: + name: iptables,iptables-netflow-dkms + + - name: Flush existing firewall rules + iptables: + flush: true + + - name: Firewall rule - allow all loopback traffic + iptables: + action: append + chain: INPUT + in_interface: lo + jump: ACCEPT + + - name: Firewall rule - allow established connections + iptables: + chain: INPUT + ctstate: ESTABLISHED,RELATED + jump: ACCEPT + + - name: Firewall rule - allow port ping traffic + iptables: + chain: INPUT + jump: ACCEPT + protocol: icmp + + - name: Firewall rule - allow port 22/SSH traffic + iptables: + chain: INPUT + destination_port: '22' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - allow port 80/HTTP traffic + iptables: + chain: INPUT + destination_port: '80' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - allow port 443/HTTPS traffic + iptables: + chain: INPUT + destination_port: '443' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - drop any traffic without rule + iptables: + chain: INPUT + jump: DROP + + - name: Flush existing firewall rules + iptables: + ip_version: ipv6 + flush: true + + - name: Firewall rule - allow all loopback traffic v6 + iptables: + ip_version: ipv6 + action: append + chain: INPUT + in_interface: lo + jump: ACCEPT + + - name: Firewall rule - allow established connections v6 + iptables: + ip_version: ipv6 + chain: INPUT + ctstate: ESTABLISHED,RELATED + jump: ACCEPT + + - name: Firewall rule - allow port ping traffic v6 + iptables: + ip_version: ipv6 + chain: INPUT + jump: ACCEPT + protocol: icmp + + - name: Firewall rule - allow port 22/SSH traffic v6 + iptables: + ip_version: ipv6 + chain: INPUT + destination_port: '22' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - allow port 80/HTTP traffic v6 + iptables: + ip_version: ipv6 + chain: INPUT + destination_port: '80' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - allow port 443/HTTPS traffic v6 + iptables: + ip_version: ipv6 + chain: INPUT + destination_port: '443' + jump: ACCEPT + protocol: tcp + + - name: Firewall rule - drop any traffic without rule v6 + iptables: + ip_version: ipv6 + chain: INPUT + jump: DROP + + handlers: + - name: restart sshd + service: + name: ssh + state: reloaded + + - name: restart postfix + service: + name: postfix + state: reloaded