everytab/infra/ec2-userdata.sh

137 lines
3.5 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# EveryTab EC2 Bootstrap
# Run this on the EC2 instance after first SSH connection.
# Installs: Go, DuckDB, Unbound, psql, pg_dump
echo "=== EveryTab EC2 Bootstrap ==="
# --- Swap ---
echo "--- Creating swap file ---"
if [ ! -f /swapfile ]; then
sudo dd if=/dev/zero of=/swapfile bs=1M count=4096
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
echo "Created 4GB swap"
else
echo "Swap already exists"
fi
# --- System packages ---
echo "--- Installing system packages ---"
sudo dnf update -y
sudo dnf install -y \
gcc \
git \
postgresql16 \
unbound \
jq \
htop \
tmux
# --- Go ---
echo "--- Installing Go ---"
GO_VERSION="1.22.4"
if ! command -v go &>/dev/null; then
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | sudo tar -C /usr/local -xz
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
fi
go version
# --- DuckDB ---
echo "--- Installing DuckDB ---"
DUCKDB_VERSION="1.5.2"
if ! command -v duckdb &>/dev/null; then
curl -fsSL "https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/duckdb_cli-linux-amd64.zip" -o /tmp/duckdb.zip
cd /tmp && unzip -o duckdb.zip && sudo mv duckdb /usr/local/bin/ && cd -
fi
duckdb -c "SELECT 'DuckDB OK';"
# Install DuckDB extensions
duckdb -c "INSTALL httpfs; INSTALL postgres;"
echo "DuckDB extensions installed"
# --- Unbound ---
echo "--- Configuring Unbound ---"
sudo tee /etc/unbound/unbound.conf > /dev/null <<'UNBOUNDCONF'
server:
interface: 127.0.0.1
port: 53
access-control: 127.0.0.0/8 allow
# Performance
num-threads: 4
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
# Cache sizing (use available RAM)
msg-cache-size: 512m
rrset-cache-size: 1g
key-cache-size: 256m
# Aggressive caching
cache-min-ttl: 3600
cache-max-ttl: 86400
prefetch: yes
prefetch-key: yes
# Hardening
hide-identity: yes
hide-version: yes
harden-glue: yes
harden-dnssec-stripped: yes
# Logging (minimal)
verbosity: 1
log-queries: no
# Root hints
root-hints: "/etc/unbound/root.hints"
remote-control:
control-enable: yes
control-interface: 127.0.0.1
UNBOUNDCONF
# Download root hints
sudo curl -fsSL https://www.internic.net/domain/named.root -o /etc/unbound/root.hints
# Disable systemd-resolved if present (it manages resolv.conf on AL2023)
if systemctl is-active --quiet systemd-resolved 2>/dev/null; then
sudo systemctl disable --now systemd-resolved
fi
# Set system resolver to use Unbound
sudo rm -f /etc/resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf > /dev/null
# Start and enable Unbound
sudo systemctl enable unbound
sudo systemctl restart unbound
# Generate control keys for unbound-control stats
sudo unbound-control-setup 2>/dev/null || true
echo ""
# --- Validation ---
echo "=== Validation ==="
echo -n "Go: "; go version
echo -n "DuckDB: "; duckdb -c "SELECT version();" -noheader -csv
echo -n "Unbound: "; dig +short example.com @127.0.0.1 | head -1
echo -n "psql: "; psql --version
echo ""
echo "=== Bootstrap Complete ==="
echo ""
echo "Next: set up your database connection string."
echo " export DATABASE_URL='postgres://everytab:PASSWORD@RDS_ENDPOINT:5432/everytab'"
echo ""
echo "Test connection:"
echo " psql \$DATABASE_URL -c 'SELECT 1;'"