Ben Sturmfels
55ee5b53b6
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.
306 lines
8 KiB
YAML
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
|