Move install path to /opt/theta42/proxy, secrets to /etc/proxy/secrets.js
- ops/install.sh now installs to /opt/theta42/proxy (was /var/www/proxy) and seeds /etc/proxy/secrets.js from secrets.js.example on first run (never overwritten on later runs), instead of requiring a manual nodejs/conf/secrets.js edit inside the repo checkout. - ops/proxy.service points at the new install path and sets CONF_SECRETS=/etc/proxy/secrets.js (requires @simpleworkjs/conf >= 1.2.0, already the pinned version) so the app picks up the secrets file with no symlink into the repo checkout. - install.sh now prints the version it's updating from/to (or "Already up to date") on every run, instead of a silent update. - Updated README/DEPLOYMENT/installation docs to match the new paths. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+14
-5
@@ -227,16 +227,25 @@ docker compose logs --tail=200 --since=10m proxy # recent context
|
|||||||
|
|
||||||
`ops/install.sh` is an idempotent installer: it installs Node.js 22.x, OpenResty
|
`ops/install.sh` is an idempotent installer: it installs Node.js 22.x, OpenResty
|
||||||
(from openresty.org), Lua modules (luarocks), Redis, force-syncs the repo to
|
(from openresty.org), Lua modules (luarocks), Redis, force-syncs the repo to
|
||||||
`/var/www/proxy`, symlinks the OpenResty + systemd config from the repo, and
|
`/opt/theta42/proxy`, symlinks the OpenResty + systemd config from the repo, and
|
||||||
starts `proxy.service`. Re-run it to update.
|
starts `proxy.service`. Re-run it to update — it prints the version you're
|
||||||
|
updating from and to (or "Already up to date" if there's nothing new).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget -O - https://raw.githubusercontent.com/theta42/proxy/master/ops/install.sh | sudo bash
|
||||||
|
```
|
||||||
|
|
||||||
|
or, if you already have the repo checked out:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo ./ops/install.sh
|
sudo ./ops/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Configuration is file-based: write `nodejs/conf/secrets.js` with the OIDC +
|
Configuration is file-based: on first run the installer seeds
|
||||||
LDAP values (see `nodejs/conf/base.js` for the shape), then
|
`/etc/proxy/secrets.js` from `secrets.js.example` (placeholders you must fill
|
||||||
`sudo systemctl restart proxy`.
|
in — OIDC + LDAP values, see `nodejs/conf/base.js` for the shape). Edit it,
|
||||||
|
then `sudo systemctl restart proxy`. Later runs never touch an existing
|
||||||
|
secrets file.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -127,10 +127,15 @@ This installer will:
|
|||||||
- Install and configure Redis
|
- Install and configure Redis
|
||||||
- Set up SSL fallback certificates
|
- Set up SSL fallback certificates
|
||||||
- Install Lua dependencies (lua-resty-auto-ssl, luasocket)
|
- Install Lua dependencies (lua-resty-auto-ssl, luasocket)
|
||||||
- Clone and install the proxy application
|
- Clone/update the proxy application at `/opt/theta42/proxy`
|
||||||
|
- Seed `/etc/proxy/secrets.js` on first run (edit it, then re-run or `systemctl restart proxy`)
|
||||||
- Configure systemd service
|
- Configure systemd service
|
||||||
- Start the proxy service
|
- Start the proxy service
|
||||||
|
|
||||||
|
It's idempotent and safe to re-run — re-running it updates the app in place and
|
||||||
|
prints the version you're updating from and to (e.g. `Updated v1.1.13 ->
|
||||||
|
v1.1.14`), or `Already up to date` if there's nothing new.
|
||||||
|
|
||||||
## Logs (Docker)
|
## Logs (Docker)
|
||||||
|
|
||||||
The all-in-one image runs OpenResty in the foreground and the Node app in the
|
The all-in-one image runs OpenResty in the foreground and the Node app in the
|
||||||
@@ -224,15 +229,24 @@ cp ops/nginx_conf/targetinfo.lua /usr/local/openresty/lualib/targetinfo.lua
|
|||||||
|
|
||||||
Clone and install:
|
Clone and install:
|
||||||
```bash
|
```bash
|
||||||
cd /var/www
|
mkdir -p /opt/theta42
|
||||||
|
cd /opt/theta42
|
||||||
git clone https://github.com/theta42/proxy.git
|
git clone https://github.com/theta42/proxy.git
|
||||||
cd proxy/nodejs
|
cd proxy/nodejs
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Configure secrets:
|
||||||
|
```bash
|
||||||
|
mkdir -p /etc/proxy
|
||||||
|
cp ../secrets.js.example /etc/proxy/secrets.js
|
||||||
|
chmod 600 /etc/proxy/secrets.js
|
||||||
|
$EDITOR /etc/proxy/secrets.js
|
||||||
|
```
|
||||||
|
|
||||||
Create systemd service:
|
Create systemd service:
|
||||||
```bash
|
```bash
|
||||||
cp ops/proxy.service /etc/systemd/system/proxy.service
|
cp ../ops/proxy.service /etc/systemd/system/proxy.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable proxy.service
|
systemctl enable proxy.service
|
||||||
systemctl start proxy.service
|
systemctl start proxy.service
|
||||||
|
|||||||
+16
-3
@@ -146,7 +146,8 @@ openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
|
|||||||
Clone the repository and copy configuration files:
|
Clone the repository and copy configuration files:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /var/www
|
mkdir -p /opt/theta42
|
||||||
|
cd /opt/theta42
|
||||||
git clone https://github.com/theta42/proxy.git
|
git clone https://github.com/theta42/proxy.git
|
||||||
cd proxy
|
cd proxy
|
||||||
|
|
||||||
@@ -161,14 +162,26 @@ cp ops/nginx_conf/targetinfo.lua /usr/local/openresty/lualib/targetinfo.lua
|
|||||||
### Step 7: Install Application
|
### Step 7: Install Application
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /var/www/proxy/nodejs
|
cd /opt/theta42/proxy/nodejs
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Step 7b: Configure Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /etc/proxy
|
||||||
|
cp /opt/theta42/proxy/secrets.js.example /etc/proxy/secrets.js
|
||||||
|
chmod 600 /etc/proxy/secrets.js
|
||||||
|
$EDITOR /etc/proxy/secrets.js # set oidc.clientId/clientSecret, ldap.bindPassword, ...
|
||||||
|
```
|
||||||
|
|
||||||
|
`@simpleworkjs/conf` reads this file via the `CONF_SECRETS` env var, which the
|
||||||
|
systemd unit below sets to `/etc/proxy/secrets.js`.
|
||||||
|
|
||||||
### Step 8: Configure Systemd Service
|
### Step 8: Configure Systemd Service
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp /var/www/proxy/ops/proxy.service /etc/systemd/system/proxy.service
|
cp /opt/theta42/proxy/ops/proxy.service /etc/systemd/system/proxy.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable proxy.service
|
systemctl enable proxy.service
|
||||||
systemctl start proxy.service
|
systemctl start proxy.service
|
||||||
|
|||||||
+45
-3
@@ -9,19 +9,26 @@
|
|||||||
# update is just "sync the repo + reload" -- the files under /etc always track
|
# update is just "sync the repo + reload" -- the files under /etc always track
|
||||||
# the repo, so there is nothing to re-copy.
|
# the repo, so there is nothing to re-copy.
|
||||||
#
|
#
|
||||||
|
# Secrets live at $SECRETS_FILE (/etc/proxy/secrets.js by default), outside the
|
||||||
|
# repo checkout so they survive the hard reset below. First run seeds it from
|
||||||
|
# secrets.js.example (placeholders you must fill in); later runs never touch
|
||||||
|
# an existing file.
|
||||||
|
#
|
||||||
# Intended to be driven by CI/CD with no human writes on prod: the checkout is
|
# Intended to be driven by CI/CD with no human writes on prod: the checkout is
|
||||||
# hard-reset to origin/$BRANCH on every run, so the box deterministically mirrors
|
# hard-reset to origin/$BRANCH on every run, so the box deterministically mirrors
|
||||||
# the repo (any drift on the box is discarded).
|
# the repo (any drift on the box is discarded).
|
||||||
#
|
#
|
||||||
# Usage: sudo ./install.sh (override with REPO_URL=, REPO_DIR=, BRANCH=)
|
# Usage: sudo ./install.sh (override with REPO_URL=, REPO_DIR=, BRANCH=,
|
||||||
|
# SECRETS_FILE=)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# Never block on an interactive git credential prompt in CI.
|
# Never block on an interactive git credential prompt in CI.
|
||||||
export GIT_TERMINAL_PROMPT=0
|
export GIT_TERMINAL_PROMPT=0
|
||||||
|
|
||||||
REPO_URL="${REPO_URL:-https://github.com/theta42/proxy.git}"
|
REPO_URL="${REPO_URL:-https://github.com/theta42/proxy.git}"
|
||||||
REPO_DIR="${REPO_DIR:-/var/www/proxy}"
|
REPO_DIR="${REPO_DIR:-/opt/theta42/proxy}"
|
||||||
BRANCH="${BRANCH:-master}"
|
BRANCH="${BRANCH:-master}"
|
||||||
NODE_MAJOR=22
|
NODE_MAJOR=22
|
||||||
|
SECRETS_FILE="${SECRETS_FILE:-/etc/proxy/secrets.js}"
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo "This script must be run as root (try: sudo $0)" >&2
|
echo "This script must be run as root (try: sudo $0)" >&2
|
||||||
@@ -34,6 +41,19 @@ link(){
|
|||||||
echo "linked $2 -> $1"
|
echo "linked $2 -> $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Read the "version" field out of a package.json without depending on Node
|
||||||
|
# being installed yet (this runs before the Node.js install step below).
|
||||||
|
pkg_version(){
|
||||||
|
sed -n 's/^[[:space:]]*"version":[[:space:]]*"\([^"]*\)".*/\1/p' "$1" | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Installed version before this run touches anything, for the upgrade banner
|
||||||
|
# at the end. Empty on a fresh install (no prior checkout).
|
||||||
|
CURRENT_VERSION=""
|
||||||
|
if [ -f "$REPO_DIR/nodejs/package.json" ]; then
|
||||||
|
CURRENT_VERSION="$(pkg_version "$REPO_DIR/nodejs/package.json")"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Base packages"
|
echo "==> Base packages"
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
@@ -134,6 +154,20 @@ else
|
|||||||
git clone --branch "$BRANCH" "$REPO_URL" "$REPO_DIR"
|
git clone --branch "$BRANCH" "$REPO_URL" "$REPO_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NEW_VERSION="$(pkg_version "$REPO_DIR/nodejs/package.json")"
|
||||||
|
|
||||||
|
echo "==> Secrets file at ${SECRETS_FILE}"
|
||||||
|
install -d -m 0750 "$(dirname "$SECRETS_FILE")"
|
||||||
|
if [ ! -f "$SECRETS_FILE" ]; then
|
||||||
|
cp "$REPO_DIR/secrets.js.example" "$SECRETS_FILE"
|
||||||
|
chmod 600 "$SECRETS_FILE"
|
||||||
|
echo " seeded ${SECRETS_FILE} from secrets.js.example -- EDIT IT before the proxy will work:"
|
||||||
|
echo " \$EDITOR ${SECRETS_FILE}"
|
||||||
|
echo " then re-run this script (or: sudo systemctl restart proxy)"
|
||||||
|
else
|
||||||
|
echo " ${SECRETS_FILE} already exists, leaving it untouched"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Symlink config from the repo"
|
echo "==> Symlink config from the repo"
|
||||||
install -d /etc/openresty/sites-enabled /var/log/nginx
|
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/nginx.conf" /etc/openresty/nginx.conf
|
||||||
@@ -162,4 +196,12 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "==> Done. Update later with: sudo BRANCH=${BRANCH} $0"
|
echo "==> Done."
|
||||||
|
if [ -z "$CURRENT_VERSION" ]; then
|
||||||
|
echo " Installed v${NEW_VERSION}."
|
||||||
|
elif [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
|
||||||
|
echo " Already up to date (v${NEW_VERSION})."
|
||||||
|
else
|
||||||
|
echo " Updated v${CURRENT_VERSION} -> v${NEW_VERSION}."
|
||||||
|
fi
|
||||||
|
echo " Update later with: sudo BRANCH=${BRANCH} $0"
|
||||||
|
|||||||
+3
-2
@@ -8,9 +8,10 @@ Type=simple
|
|||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=1
|
RestartSec=1
|
||||||
User=root
|
User=root
|
||||||
WorkingDirectory=/var/www/proxy/nodejs
|
WorkingDirectory=/opt/theta42/proxy/nodejs
|
||||||
Environment="NODE_ENV=production"
|
Environment="NODE_ENV=production"
|
||||||
ExecStart=/usr/bin/env node /var/www/proxy/nodejs/bin/www
|
Environment="CONF_SECRETS=/etc/proxy/secrets.js"
|
||||||
|
ExecStart=/usr/bin/env node /opt/theta42/proxy/nodejs/bin/www
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
+7
-4
@@ -6,13 +6,16 @@
|
|||||||
// direct LDAP client for user lookups. This file supplies that wiring.
|
// direct LDAP client for user lookups. This file supplies that wiring.
|
||||||
//
|
//
|
||||||
// Docker / unified stack: place at ./config/proxy-secrets.js and bind-mount
|
// Docker / unified stack: place at ./config/proxy-secrets.js and bind-mount
|
||||||
// ./config at /config (see docker-compose.yml); docker-entrypoint.sh symlinks
|
// ./config at /config (see docker-compose.yml); docker-entrypoint.sh points the
|
||||||
// it into /app/conf/secrets.js so @simpleworkjs/conf reads it. No app_* env
|
// CONF_SECRETS env var at it so @simpleworkjs/conf reads it. No app_* env
|
||||||
// should be passed — app_* env beats this file in @simpleworkjs/conf, so the
|
// should be passed — app_* env beats this file in @simpleworkjs/conf, so the
|
||||||
// file is authoritative only if the matching app_* env is absent.
|
// file is authoritative only if the matching app_* env is absent.
|
||||||
//
|
//
|
||||||
// Bare-metal: copy to nodejs/conf/secrets.js and fill in your values. Values
|
// Bare-metal: ops/install.sh seeds this file at /etc/proxy/secrets.js on first
|
||||||
// here override conf/base.js and win over <environment>.js.
|
// run (with placeholders for the values it can't guess) and points the
|
||||||
|
// systemd unit's CONF_SECRETS env var at it. Fill in your values, then
|
||||||
|
// `sudo systemctl restart proxy`. Values here override conf/base.js and win
|
||||||
|
// over <environment>.js.
|
||||||
//
|
//
|
||||||
// Only the keys the app reads are listed below. The `stack` key is read by the
|
// Only the keys the app reads are listed below. The `stack` key is read by the
|
||||||
// theta-env orchestrator (setup.sh) and ignored by the app.
|
// theta-env orchestrator (setup.sh) and ignored by the app.
|
||||||
|
|||||||
Reference in New Issue
Block a user