# 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