#!/bin/sh # # install-disc.sh — non-interactive Disc install + systemd deployment. # POSIX sh compatible: safe to run as `curl -fsSL .../install-disc.sh | sh`. # Run as root, or as a user with passwordless sudo. # # Override any of these at invocation time, e.g. # curl -fsSL .../install-disc.sh | DISC_PORT=6000 DISC_HOST=0.0.0.0 sh # DISC_PREFIX=/srv/disc DISC_USER=discd ./install-disc.sh # set -eu # Enable pipefail only when the shell supports it (dash >= 0.5.12, bash, etc.). (set -o pipefail) 2>/dev/null && set -o pipefail # --- Tunables (override via environment) ------------------------------------- DISC_USER="${DISC_USER:-disc}" DISC_PROJECT="${DISC_PROJECT:-disc}" # project + managed-instance + db name DISC_PREFIX="${DISC_PREFIX:-/opt/disc}" DISC_ETC="${DISC_ETC:-/etc/disc}" DISC_HOME="${DISC_HOME:-${DISC_PREFIX}}" DISC_HOST="${DISC_HOST:-127.0.0.1}" DISC_PORT="${DISC_PORT:-5656}" DATABASE_URL="${DATABASE_URL:-}" # leave empty to use bundled PostgreSQL DEPLOY_DIR="${DEPLOY_DIR:-/tmp/disc-deploy}" # ----------------------------------------------------------------------------- DISC_ENV="${DISC_ETC}/disc.env" # Use sudo only when we are not already root, so the script runs either way. SUDO="" if [ "$(id -u)" -ne 0 ]; then SUDO="sudo" fi # 1. Create a dedicated, login-less system user (skip if it already exists). # --system also creates a matching group named "${DISC_USER}", which the # unit's Group= directive relies on. if ! id "${DISC_USER}" >/dev/null 2>&1; then ${SUDO} useradd --system --create-home --shell /usr/sbin/nologin "${DISC_USER}" fi # 2. Install Disc. ${SUDO} env DISC_INSTALL="${DISC_PREFIX}" sh -c \ 'curl -fsSL https://disc.sh/install | sh -s -- --no-modify-path --no-man' # Ensure the system user owns the installation directory. ${SUDO} chown -R "${DISC_USER}:${DISC_USER}" "${DISC_PREFIX}" # 3. Write the environment file the unit reads (EnvironmentFile=/etc/disc/disc.env). # Unquoted heredoc so the variables above expand; literal $ in comments is escaped. ${SUDO} mkdir -p "${DISC_ETC}" ${SUDO} tee "${DISC_ENV}" >/dev/null </dev/null fi ${SUDO} chown "${DISC_USER}:${DISC_USER}" "${DISC_ENV}" ${SUDO} chmod 0640 "${DISC_ENV}" # 3b. Write the project config the server resolves at startup. Without a # disc.toml on (or above) the unit's WorkingDirectory, `disc serve` finds # no project context, skips starting the bundled PostgreSQL entirely, and # falls back to a TCP DSN nothing is listening on (ConnectionRefused). It # must live at ${DISC_HOME}/disc.toml because the unit's WorkingDirectory is # ${DISC_HOME} and the server walks UP from there to find it. We write it by # hand rather than `disc init` -- init scaffolds dev files, nests the project # in a subdirectory, and creates the instance in the default HOME location. if [ -n "${DATABASE_URL}" ]; then DB_BLOCK="# External PostgreSQL -- disc does not manage the instance lifecycle managed = false backend_dsn = \"${DATABASE_URL}\"" else DB_BLOCK="# Managed PostgreSQL instance (bundled, started by disc serve) managed = true instance_name = \"${DISC_PROJECT}\"" fi ${SUDO} tee "${DISC_HOME}/disc.toml" >/dev/null <&2 ${SUDO} systemctl enable --now disc # 5. Verify it came up as the disc user, not root. ${SUDO} systemctl status disc --no-pager