Matchu
e70e67211e
Idk why it's memory leaking so hard lately? But let's uhhh just reboot it a ton for now, while we continue to work on migrating workloads offa there.
348 lines
11 KiB
YAML
348 lines
11 KiB
YAML
---
|
|
- name: Set up the environment for the impress-2020 app
|
|
hosts: webserver
|
|
vars:
|
|
email_address: "emi@matchu.dev" # TODO: Extract this to personal config?
|
|
tasks:
|
|
- name: Copy authorized SSH keys
|
|
copy:
|
|
dest: ~/.ssh/authorized_keys
|
|
src: ../authorized-ssh-keys.txt
|
|
|
|
- name: Disable root SSH login
|
|
become: yes
|
|
lineinfile:
|
|
dest: /etc/ssh/sshd_config
|
|
regexp: ^#?PermitRootLogin
|
|
line: PermitRootLogin no
|
|
|
|
- name: Disable password-based SSH authentication
|
|
become: yes
|
|
lineinfile:
|
|
dest: /etc/ssh/sshd_config
|
|
regexp: ^#?PasswordAuthentication
|
|
line: PasswordAuthentication no
|
|
|
|
- name: Install fail2ban firewall with default settings
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name: fail2ban
|
|
|
|
- name: Configure ufw firewall to allow SSH connections on port 22
|
|
become: yes
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "22"
|
|
|
|
- name: Configure ufw firewall to allow HTTP connections on port 80
|
|
become: yes
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "80"
|
|
|
|
- name: Configure ufw firewall to allow HTTP connections on port 443
|
|
become: yes
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "443"
|
|
|
|
- name: Enable ufw firewall with all other ports closed by default
|
|
become: yes
|
|
community.general.ufw:
|
|
state: enabled
|
|
policy: deny
|
|
|
|
- name: Install unattended-upgrades
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name: unattended-upgrades
|
|
|
|
- name: Enable unattended-upgrades to auto-upgrade our system
|
|
become: yes
|
|
copy:
|
|
content: |
|
|
APT::Periodic::Update-Package-Lists "1";
|
|
APT::Periodic::Unattended-Upgrade "1";
|
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
|
|
|
- name: Configure unattended-upgrades to auto-reboot our server when necessary
|
|
become: yes
|
|
lineinfile:
|
|
regex: ^(//\s*)?Unattended-Upgrade::Automatic-Reboot ".*";$
|
|
line: Unattended-Upgrade::Automatic-Reboot "true";
|
|
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
|
|
|
- name: Configure unattended-upgrades to delay necessary reboots to 3am
|
|
become: yes
|
|
lineinfile:
|
|
regex: ^(//\s*)?Unattended-Upgrade::Automatic-Reboot-Time ".*";$
|
|
line: Unattended-Upgrade::Automatic-Reboot-Time "03:00";
|
|
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
|
|
|
- name: Configure the system timezone to be US Pacific time
|
|
become: yes
|
|
community.general.timezone:
|
|
name: America/Los_Angeles
|
|
|
|
- name: Create the app versions folder
|
|
become: yes
|
|
file:
|
|
path: /srv/impress-2020/versions
|
|
owner: "{{ ansible_user_id }}"
|
|
group: "{{ ansible_user_id }}"
|
|
state: directory
|
|
|
|
- name: Add Nodesource apt key
|
|
become: yes
|
|
apt_key:
|
|
id: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280
|
|
url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key
|
|
|
|
- name: Add Node v16 apt repository
|
|
become: yes
|
|
apt_repository:
|
|
repo: deb https://deb.nodesource.com/node_16.x focal main
|
|
|
|
- name: Install Node v16
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name: nodejs
|
|
|
|
- name: Install Yarn
|
|
become: yes
|
|
npm:
|
|
name: yarn
|
|
global: yes
|
|
|
|
- name: Check for a current app version
|
|
stat:
|
|
path: /srv/impress-2020/current
|
|
register: current_app_version
|
|
|
|
- name: Check whether we already have a placeholder app
|
|
stat:
|
|
path: /srv/impress-2020/versions/initial-placeholder
|
|
register: existing_placeholder_app
|
|
when: not current_app_version.stat.exists
|
|
|
|
- name: Create a placeholder app, to run until we deploy a real version
|
|
command:
|
|
chdir: /srv/impress-2020/versions
|
|
cmd: yarn create next-app initial-placeholder
|
|
when: |
|
|
not current_app_version.stat.exists and
|
|
not existing_placeholder_app.stat.exists
|
|
|
|
- name: Build the placeholder app
|
|
command:
|
|
chdir: /srv/impress-2020/versions/initial-placeholder
|
|
cmd: yarn build
|
|
when: not current_app_version.stat.exists
|
|
|
|
- name: Set the placeholder app as the current version
|
|
file:
|
|
src: /srv/impress-2020/versions/initial-placeholder
|
|
dest: /srv/impress-2020/current
|
|
state: link
|
|
when: not current_app_version.stat.exists
|
|
|
|
- name: Install pm2
|
|
become: yes
|
|
npm:
|
|
name: pm2
|
|
global: yes
|
|
|
|
- name: Create pm2 startup script
|
|
# The current user is going to become the pm2 owner of the app server
|
|
# process. They'll be able to manage it without `sudo`, including during
|
|
# normal deploys, and run `pm2 monit` from their shell to see status.
|
|
become: yes
|
|
command: "pm2 startup systemd -u {{ ansible_user_id }} --hp /home/{{ ansible_user_id }}"
|
|
|
|
- name: Create pm2 ecosystem file
|
|
copy:
|
|
content: |
|
|
module.exports = {
|
|
apps: [
|
|
{
|
|
name: "impress-2020",
|
|
cwd: "/srv/impress-2020/current",
|
|
// Instead of `yarn start`, we specify the `next` binary
|
|
// directly, because it helps pm2 monitor our app correctly.
|
|
// https://github.com/vercel/next.js/discussions/10675#discussioncomment-34615
|
|
script: "./node_modules/.bin/next",
|
|
args: "start --port=3000",
|
|
instances: "max",
|
|
exec_mode: "cluster",
|
|
}
|
|
]
|
|
}
|
|
dest: "~/ecosystem.config.js"
|
|
# Create a temporary backup file, so we can use it to delete the old
|
|
# version of the services. (This is important if e.g. a service is
|
|
# removed or renamed, in which case deleting from the *new* config file
|
|
# wouldn't include it.)
|
|
backup: yes
|
|
register: pm2_ecosystem_file
|
|
|
|
- name: Delete old pm2 services if config file changed
|
|
command: "pm2 delete {{ pm2_ecosystem_file.backup_file | quote }}"
|
|
when: pm2_ecosystem_file is changed and pm2_ecosystem_file.backup_file is defined
|
|
|
|
- name: Delete old pm2 config file if it changed
|
|
file:
|
|
path: "{{ pm2_ecosystem_file.backup_file }}"
|
|
state: absent
|
|
when: pm2_ecosystem_file is changed and pm2_ecosystem_file.backup_file is defined
|
|
|
|
- name: Start pm2 services
|
|
command: "pm2 start ~/ecosystem.config.js"
|
|
|
|
- name: Save pm2 startup script
|
|
command: pm2 save
|
|
|
|
- name: Install nginx
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name: nginx
|
|
|
|
- name: Install core snap
|
|
become: yes
|
|
community.general.snap:
|
|
name: core
|
|
|
|
- name: Install certbot as a snap
|
|
become: yes
|
|
community.general.snap:
|
|
name: certbot
|
|
classic: yes
|
|
|
|
- name: Set up certbot
|
|
become: yes
|
|
command: "certbot certonly --nginx -n --agree-tos --email {{ email_address }} --domains impress-2020-box.openneo.net"
|
|
|
|
- name: Add impress-2020 config file to nginx
|
|
become: yes
|
|
copy:
|
|
content: |
|
|
server {
|
|
server_name impress-2020-box.openneo.net;
|
|
listen 80;
|
|
if ($host = impress-2020-box.openneo.net) {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
|
|
server {
|
|
server_name impress-2020-box.openneo.net;
|
|
listen 443 ssl;
|
|
ssl_certificate /etc/letsencrypt/live/impress-2020-box.openneo.net/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/impress-2020-box.openneo.net/privkey.pem;
|
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
ssl_session_cache shared:SSL:10m; # https://superuser.com/q/1484466/14127
|
|
|
|
# TODO: Serve static files directly, instead of through the proxy
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3000;
|
|
}
|
|
}
|
|
dest: /etc/nginx/sites-enabled/impress-2020
|
|
notify:
|
|
- Restart nginx
|
|
|
|
- name: Create cron log files directory
|
|
file:
|
|
path: /srv/impress-2020/cron-logs
|
|
state: directory
|
|
|
|
- name: Set up modeling cron jobs
|
|
cron:
|
|
name: model-needed-items
|
|
minute: "*/10" # Every 10 minutes
|
|
job: "cd /srv/impress-2020/current && yarn model-needed-items 2>&1 > /srv/impress-2020/cron-logs/model-needed-items.log"
|
|
|
|
# Idk why the app has been so memory leaky lately, but let's just restart it
|
|
# like *constantly* tbh.
|
|
- name: Set up cron job to restart the app
|
|
cron:
|
|
name: restart-impress-2020
|
|
minute: "*/8" # Every 8 minutes
|
|
job: "pm2 restart impress-2020"
|
|
|
|
- name: Install dependencies for the npm module node-canvas
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name:
|
|
- build-essential
|
|
- libcairo2-dev
|
|
- libpango1.0-dev
|
|
- libjpeg-dev
|
|
- libgif-dev
|
|
- librsvg2-dev
|
|
- name: Install Playwright system dependencies
|
|
# NOTE: I copied the package list from the source list for
|
|
# `npx playwright install-deps`, which I couldn't get running in
|
|
# Ansible as root, and besides, I prefer manually managing the
|
|
# package list over running an npm script as root!
|
|
# TODO: We're using Puppeteer now, should this list change in some way?
|
|
become: yes
|
|
apt:
|
|
update_cache: yes
|
|
name:
|
|
# Tools
|
|
- xvfb
|
|
- fonts-noto-color-emoji
|
|
- ttf-unifont
|
|
- libfontconfig
|
|
- libfreetype6
|
|
- xfonts-cyrillic
|
|
- xfonts-scalable
|
|
- fonts-liberation
|
|
- fonts-ipafont-gothic
|
|
- fonts-wqy-zenhei
|
|
- fonts-tlwg-loma-otf
|
|
- ttf-ubuntu-font-family
|
|
# Chromium
|
|
- fonts-liberation
|
|
- libasound2
|
|
- libatk-bridge2.0-0
|
|
- libatk1.0-0
|
|
- libatspi2.0-0
|
|
- libcairo2
|
|
- libcups2
|
|
- libdbus-1-3
|
|
- libdrm2
|
|
- libegl1
|
|
- libgbm1
|
|
- libglib2.0-0
|
|
- libgtk-3-0
|
|
- libnspr4
|
|
- libnss3
|
|
- libpango-1.0-0
|
|
- libx11-6
|
|
- libx11-xcb1
|
|
- libxcb1
|
|
- libxcomposite1
|
|
- libxdamage1
|
|
- libxext6
|
|
- libxfixes3
|
|
- libxrandr2
|
|
- libxshmfence1
|
|
- name: Enable user namespace cloning for Chromium sandboxing
|
|
become: yes
|
|
ansible.posix.sysctl:
|
|
name: kernel.unprivileged_userns_clone
|
|
value: "1"
|
|
|
|
handlers:
|
|
- name: Restart nginx
|
|
become: yes
|
|
systemd:
|
|
name: nginx
|
|
state: restarted
|