Make ops/install.sh idempotent and symlink config from the repo

Rework the installer so it doubles as an updater:

- Idempotent throughout: `install -d` for dirs, apt source lists rewritten
  in place, `gpg --dearmor --yes`, fallback cert generated only if missing,
  repo cloned or fast-forwarded, and `ln -sfn` symlinks.
- Config is now symlinked straight from the checked-out repo instead of
  wget-ing raw files from GitHub. /etc/openresty/{nginx.conf,autossl.conf,
  sites-enabled/000-proxy}, the targetinfo.lua lualib, and the systemd unit
  all point at $REPO_DIR/ops, so an update is just `git pull` + reload with
  no re-copying. This also drops the external t42-common raw-file
  dependency (autossl.conf / proxy.conf now come from this repo).
- Validate `openresty -t` before reloading so a bad config can't take the
  proxy down; reload if running else restart.
- Fix prior bugs: stray `curl sudo apt-get update`, duplicate openssl cert
  line, and `cd ../nodejs` (now cd $REPO_DIR/nodejs). Require root; add a
  BRANCH override (default master).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 13:14:48 -04:00
parent 9f175f5bf6
commit ec168411bf
Regular → Executable
+89 -37
View File
@@ -1,52 +1,104 @@
#!/usr/bin/env bash
#
# Install / update the Theta42 proxy on a fresh or existing host.
#
# This script is idempotent: run it to install, and re-run it to update. It
# installs system dependencies (Node, OpenResty, Redis, Lua modules), checks
# out (or fast-forwards) the repo at $REPO_DIR, and symlinks the OpenResty and
# systemd config straight from the repo. Because the config is symlinked, an
# update is just "git pull + reload" -- the files under /etc always track the
# repo, so there is nothing to re-copy.
#
# Usage: sudo ./install.sh
set -euo pipefail
apt install libpam0g-dev build-essential redis-server luarocks --no-install-recommends wget gnupg ca-certificates curl git -y
REPO_URL="https://github.com/theta42/proxy.git"
REPO_DIR="/var/www/proxy"
BRANCH="${BRANCH:-master}"
NODE_MAJOR=22
curl sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root (try: sudo $0)" >&2
exit 1
fi
sudo apt-get install -y nodejs
# Symlink $1 -> $2, replacing whatever is already at $2 (idempotent).
link(){
ln -sfn "$1" "$2"
echo "linked $2 -> $1"
}
echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list
echo "==> Base packages"
apt-get update
apt-get install -y --no-install-recommends \
libpam0g-dev build-essential redis-server luarocks \
wget gnupg ca-certificates curl git lsb-release
sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates #cert
echo "==> Node.js ${NODE_MAJOR}.x apt source"
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list
wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg #importing gpg key
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list > /dev/null
echo "==> OpenResty apt source"
wget -qO- https://openresty.org/package/pubkey.gpg \
| gpg --dearmor --yes -o /usr/share/keyrings/openresty.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" \
> /etc/apt/sources.list.d/openresty.list
sudo apt-get update
echo "==> Install Node.js + OpenResty"
apt-get update
apt-get install -y nodejs openresty
sudo apt-get -y install openresty
echo "==> Lua modules"
luarocks install lua-resty-auto-ssl
luarocks install luasocket
echo "==> Fallback SSL cert"
install -d /etc/ssl
if [ ! -f /etc/ssl/resty-auto-ssl-fallback.crt ]; then
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
-subj '/CN=sni-support-required-for-valid-ssl' \
-keyout /etc/ssl/resty-auto-ssl-fallback.key \
-out /etc/ssl/resty-auto-ssl-fallback.crt
else
echo "fallback cert already present, skipping"
fi
sudo luarocks install lua-resty-auto-ssl
sudo luarocks install luasocket
echo "==> Repo checkout at ${REPO_DIR} (branch ${BRANCH})"
install -d "$(dirname "$REPO_DIR")"
if [ -d "$REPO_DIR/.git" ]; then
git -C "$REPO_DIR" fetch --prune origin
git -C "$REPO_DIR" checkout "$BRANCH"
git -C "$REPO_DIR" pull --ff-only origin "$BRANCH"
else
git clone --branch "$BRANCH" "$REPO_URL" "$REPO_DIR"
fi
mkdir /etc/ssl/
echo "==> Symlink config from the repo"
install -d /etc/openresty/sites-enabled /var/log/nginx
link "$REPO_DIR/ops/nginx_conf/nginx.conf" /etc/openresty/nginx.conf
link "$REPO_DIR/ops/nginx_conf/autossl.conf" /etc/openresty/autossl.conf
link "$REPO_DIR/ops/nginx_conf/proxy.conf" /etc/openresty/sites-enabled/000-proxy
link "$REPO_DIR/ops/nginx_conf/targetinfo.lua" /usr/local/openresty/lualib/targetinfo.lua
link "$REPO_DIR/ops/proxy.service" /etc/systemd/system/proxy.service
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt
echo "==> Node dependencies"
( cd "$REPO_DIR/nodejs" && npm install )
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt
echo "==> Services"
systemctl daemon-reload
systemctl enable --now proxy.service
systemctl restart proxy.service
mkdir /etc/openresty/sites-enabled/
wget -q https://raw.githubusercontent.com/theta42/proxy/refs/heads/master/ops/nginx_conf/nginx.conf -O /etc/openresty/nginx.conf
wget -q https://raw.githubusercontent.com/theta42/t42-common/master/templates/openresty/autossl.conf.erb -O /etc/openresty/autossl.conf
wget -q https://raw.githubusercontent.com/theta42/t42-common/master/templates/openresty/010-proxy.conf.erb -O /etc/openresty/sites-enabled/000-proxy
wget -q https://raw.githubusercontent.com/theta42/proxy/master/ops/proxy.service -O /etc/systemd/system/proxy.service
# Validate the OpenResty config before (re)starting so a bad edit can't take
# the proxy down; reload if already running, otherwise start it.
if openresty -t; then
systemctl reload openresty 2>/dev/null || systemctl restart openresty
else
echo "openresty config test FAILED -- not reloading" >&2
exit 1
fi
mkdir /var/log/nginx
mkdir /var/www
cd /var/www
git clone https://github.com/theta42/proxy.git
cd proxy/nodejs
npm install
wget -q https://raw.githubusercontent.com/theta42/proxy/refs/heads/master/ops/nginx_conf/targetinfo.lua -O /usr/local/openresty/lualib/targetinfo.lua
systemctl start proxy.service
systemctl enable proxy.service
echo "==> Done. Update later with: sudo BRANCH=${BRANCH} $0"