#!/bin/sh set -eu SOURCE_DIR=${POBSYNC_SOURCE_DIR:-$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)} APP_DIR=${POBSYNC_APP_DIR:-/opt/pobsync/app} VENV_DIR=${POBSYNC_VENV_DIR:-/opt/pobsync/venv} ENV_FILE=${POBSYNC_ENV_FILE:-/etc/pobsync/pobsync.env} SERVICE_USER=${POBSYNC_SERVICE_USER:-pobsync} SERVICE_GROUP=${POBSYNC_SERVICE_GROUP:-pobsync} INSTALL_EXTRAS=${POBSYNC_INSTALL_EXTRAS:-} SERVER_NAME=${POBSYNC_SERVER_NAME:-_} ALLOWED_HOSTS=${POBSYNC_ALLOWED_HOSTS:-localhost,127.0.0.1} CSRF_TRUSTED_ORIGINS=${POBSYNC_CSRF_TRUSTED_ORIGINS:-} BACKUP_ROOT=${POBSYNC_BACKUP_ROOT:-/backups} WEB_BIND=${POBSYNC_WEB_BIND:-127.0.0.1:8010} FORCE_ENV=0 INSTALL_OS_PACKAGES=1 WITH_NGINX=0 while [ "$#" -gt 0 ]; do case "$1" in --source-dir) SOURCE_DIR=$2 shift 2 ;; --app-dir) APP_DIR=$2 shift 2 ;; --venv-dir) VENV_DIR=$2 shift 2 ;; --env-file) ENV_FILE=$2 shift 2 ;; --service-user) SERVICE_USER=$2 shift 2 ;; --service-group) SERVICE_GROUP=$2 shift 2 ;; --backup-root) BACKUP_ROOT=$2 shift 2 ;; --allowed-hosts) ALLOWED_HOSTS=$2 shift 2 ;; --csrf-trusted-origins) CSRF_TRUSTED_ORIGINS=$2 shift 2 ;; --web-bind) WEB_BIND=$2 shift 2 ;; --force-env) FORCE_ENV=1 shift ;; --no-install-os-packages) INSTALL_OS_PACKAGES=0 shift ;; --install-extras) INSTALL_EXTRAS=$2 shift 2 ;; --with-nginx) WITH_NGINX=1 shift ;; --server-name) SERVER_NAME=$2 shift 2 ;; *) echo "Unknown argument: $1" >&2 exit 2 ;; esac done if [ "$(id -u)" -ne 0 ]; then echo "Run this installer as root." >&2 exit 1 fi install_os_packages() { if [ "$INSTALL_OS_PACKAGES" -ne 1 ]; then return fi if command -v apt-get >/dev/null 2>&1; then packages="python3 python3-venv python3-pip rsync openssh-client" if [ "$WITH_NGINX" -eq 1 ]; then packages="$packages nginx" fi if [ "$INSTALL_EXTRAS" = "mariadb" ] || [ "$INSTALL_EXTRAS" = "[mariadb]" ] || [ "$INSTALL_EXTRAS" = ".[mariadb]" ]; then packages="$packages default-libmysqlclient-dev build-essential pkg-config" fi apt-get update apt-get install -y --no-install-recommends $packages return fi echo "No supported package manager found; install python3, python3-venv, rsync, and openssh-client manually." >&2 } install_os_packages if ! command -v python3 >/dev/null 2>&1; then echo "python3 is required." >&2 exit 1 fi if ! command -v rsync >/dev/null 2>&1; then echo "rsync is required." >&2 exit 1 fi if ! command -v ssh >/dev/null 2>&1; then echo "openssh-client is required." >&2 exit 1 fi if [ ! -f "$SOURCE_DIR/manage.py" ]; then echo "Source directory does not look like a pobsync checkout: $SOURCE_DIR" >&2 exit 1 fi if ! getent group "$SERVICE_GROUP" >/dev/null 2>&1; then groupadd --system "$SERVICE_GROUP" fi if ! id "$SERVICE_USER" >/dev/null 2>&1; then useradd --system --home /var/lib/pobsync --shell /usr/sbin/nologin --gid "$SERVICE_GROUP" "$SERVICE_USER" fi mkdir -p /etc/pobsync /var/lib/pobsync /var/log/pobsync "$(dirname "$VENV_DIR")" "$APP_DIR" "$BACKUP_ROOT" chown "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync chmod 0750 /var/lib/pobsync /var/log/pobsync if [ "$SOURCE_DIR" != "$APP_DIR" ]; then rsync -a --delete \ --exclude .git \ --exclude .venv \ --exclude __pycache__ \ --exclude .pytest_cache \ --exclude .mypy_cache \ --exclude var \ "$SOURCE_DIR"/ "$APP_DIR"/ fi python3 -m venv "$VENV_DIR" "$VENV_DIR/bin/python" -m pip install --upgrade pip case "$INSTALL_EXTRAS" in "") pip_target=$APP_DIR ;; mariadb) pip_target="$APP_DIR[mariadb]" ;; \[*\]) pip_target="$APP_DIR$INSTALL_EXTRAS" ;; .\[*\]) pip_target="$APP_DIR${INSTALL_EXTRAS#.}" ;; *) echo "Unsupported install extras: $INSTALL_EXTRAS" >&2 exit 2 ;; esac "$VENV_DIR/bin/python" -m pip install -e "$pip_target" if [ ! -f "$ENV_FILE" ] || [ "$FORCE_ENV" -eq 1 ]; then secret=$("$VENV_DIR/bin/python" -c "import secrets; print(secrets.token_urlsafe(48))") cat > "$ENV_FILE" < "$dest" chmod 0644 "$dest" } install_unit "$APP_DIR/deploy/systemd/pobsync-web.service" /etc/systemd/system/pobsync-web.service install_unit "$APP_DIR/deploy/systemd/pobsync-worker.service" /etc/systemd/system/pobsync-worker.service install_unit "$APP_DIR/deploy/systemd/pobsync-scheduler.service" /etc/systemd/system/pobsync-scheduler.service systemctl daemon-reload "$VENV_DIR/bin/python" "$APP_DIR/manage.py" migrate --noinput "$VENV_DIR/bin/python" "$APP_DIR/manage.py" collectstatic --noinput --clear systemctl enable --now pobsync-web.service pobsync-worker.service pobsync-scheduler.service if [ "$WITH_NGINX" -eq 1 ]; then if ! command -v nginx >/dev/null 2>&1; then echo "nginx is not installed; skipping nginx config." >&2 else sed "s|@POBSYNC_SERVER_NAME@|$SERVER_NAME|g" "$APP_DIR/deploy/nginx/pobsync.conf" > /etc/nginx/sites-available/pobsync.conf ln -sf /etc/nginx/sites-available/pobsync.conf /etc/nginx/sites-enabled/pobsync.conf nginx -t systemctl reload nginx fi fi systemctl --no-pager --full status pobsync-web.service pobsync-worker.service pobsync-scheduler.service || true