infra/burst/state/setup-web-server.sh (3012 bytes)
1 #!/bin/bash 2 # Set up the shared state of burst mode on the web server (Debian 12): 3 # 4 # - Postgres on 127.0.0.1: role and database "subplz". 5 # - Redis on 127.0.0.1, with a password, and a journal on disk. 6 # - The user "subplz-tunnel": burst workers log in as this user only to 7 # forward two ports (Postgres and Redis). No shell, no other port. 8 # - A nightly Postgres backup to the bucket (enabled by the runbook). 9 # 10 # Terraform (main.tf) runs this script on the web server itself. It is 11 # idempotent: a second run changes nothing. Input: POSTGRES_PASSWORD, 12 # REDIS_PASSWORD, TUNNEL_PUBLIC_KEY in the environment. 13 set -euo pipefail 14 : "${POSTGRES_PASSWORD:?}" "${REDIS_PASSWORD:?}" "${TUNNEL_PUBLIC_KEY:?}" 15 16 export DEBIAN_FRONTEND=noninteractive 17 apt-get update -q 18 apt-get install -y -q postgresql redis-server rclone 19 20 # --- Postgres: the Debian package listens on localhost only. ----------------- 21 runuser -u postgres -- psql -q -v ON_ERROR_STOP=1 -v pw="$POSTGRES_PASSWORD" <<'SQL' 22 SELECT 'CREATE ROLE subplz LOGIN' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'subplz')\gexec 23 ALTER ROLE subplz PASSWORD :'pw'; 24 SELECT 'CREATE DATABASE subplz OWNER subplz' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'subplz')\gexec 25 SQL 26 27 # --- Redis: localhost only, a password, and a journal (the queue survives a restart). 28 conf=/etc/redis/redis.conf 29 set_conf() { 30 if grep -q "^$1 " "$conf"; then 31 sed -i "s|^$1 .*|$1 $2|" "$conf" 32 else 33 echo "$1 $2" >> "$conf" 34 fi 35 } 36 set_conf bind "127.0.0.1 -::1" 37 set_conf requirepass "$REDIS_PASSWORD" 38 set_conf appendonly yes 39 systemctl restart redis-server 40 41 # --- The tunnel user. --------------------------------------------------------- 42 if ! id subplz-tunnel >/dev/null 2>&1; then 43 useradd --system --create-home --shell /usr/sbin/nologin subplz-tunnel 44 fi 45 home=$(getent passwd subplz-tunnel | cut -d: -f6) 46 install -d -m 700 -o subplz-tunnel -g subplz-tunnel "$home/.ssh" 47 printf 'restrict,port-forwarding,permitopen="127.0.0.1:5432",permitopen="127.0.0.1:6379" %s\n' \ 48 "$TUNNEL_PUBLIC_KEY" > "$home/.ssh/authorized_keys" 49 chown subplz-tunnel:subplz-tunnel "$home/.ssh/authorized_keys" 50 chmod 600 "$home/.ssh/authorized_keys" 51 52 # --- Nightly backup of Postgres to the bucket. The runbook writes 53 # /etc/subplz-rclone.env and /etc/subplz-backup.env, then enables the timer. 54 cat > /etc/systemd/system/subplz-pgdump.service <<'UNIT' 55 [Unit] 56 Description=Back up the subplz Postgres database to the bucket 57 58 [Service] 59 Type=oneshot 60 EnvironmentFile=/etc/subplz-rclone.env 61 EnvironmentFile=/etc/subplz-backup.env 62 ExecStart=/bin/bash -c 'set -o pipefail; runuser -u postgres -- pg_dump -Fc subplz | rclone rcat "r2:$BUCKET/backups/subplz-$(date -u +%%Y%%m%%d).dump"' 63 UNIT 64 cat > /etc/systemd/system/subplz-pgdump.timer <<'UNIT' 65 [Unit] 66 Description=Back up the subplz Postgres database each night 67 68 [Timer] 69 OnCalendar=*-*-* 04:30:00 70 Persistent=true 71 72 [Install] 73 WantedBy=timers.target 74 UNIT 75 systemctl daemon-reload 76 echo "web server ready: Postgres, Redis, tunnel user"