website/bin/deploy/install.yml
Ben Sturmfels 55ee5b53b6
Add a basic script to "push" deploy
Currently updates are published by the "conservancy-www-update.sh" that does a
"pull" deploy with a 5-minutely job that runs on the web server. This doesn't
run `migrate`, `collectstatic` or restart the application, so certain types of
changes don't take effect, and even template changes often don't due to caching
template loader.

This script allows you to deploy more significant updates on-demand, but
requires SSH access.
2024-02-23 15:39:54 +11:00

306 lines
8 KiB
YAML

# 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