Files
pobsync/scripts/install-systemd
Peter van Arkel b1789d8621 (config) Install native runtime requirements and split docs
Teach the systemd installer to install required Debian/Ubuntu
packages by default, with an opt-out for users who manage system
dependencies themselves.

Add explicit MariaDB install-extra handling so native installs can
pull in both the Python extra and required client build packages.

Slim down the README to production setup and operations, and move
development, Docker, migration helper, and architecture notes into
docs/development.md.
2026-05-19 18:15:34 +02:00

242 lines
6.8 KiB
Bash
Executable File

#!/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" <<EOF
POBSYNC_DJANGO_DEBUG=0
POBSYNC_DJANGO_SECRET_KEY=$secret
POBSYNC_DJANGO_ALLOWED_HOSTS=$ALLOWED_HOSTS
POBSYNC_DJANGO_CSRF_TRUSTED_ORIGINS=$CSRF_TRUSTED_ORIGINS
POBSYNC_HOME=/var/lib/pobsync
POBSYNC_BACKUP_ROOT=$BACKUP_ROOT
POBSYNC_SQLITE_PATH=/var/lib/pobsync/pobsync.sqlite3
POBSYNC_STATIC_ROOT=/var/lib/pobsync/static
POBSYNC_WEB_BIND=$WEB_BIND
POBSYNC_GUNICORN_WORKERS=2
POBSYNC_GUNICORN_TIMEOUT=120
POBSYNC_WORKER_INTERVAL=15
POBSYNC_SCHEDULER_INTERVAL=60
EOF
chmod 0640 "$ENV_FILE"
chown "root:$SERVICE_GROUP" "$ENV_FILE"
echo "Wrote $ENV_FILE."
else
echo "Keeping existing $ENV_FILE. Use --force-env to rewrite it."
fi
install_unit() {
src=$1
dest=$2
sed \
-e "s|@POBSYNC_APP_DIR@|$APP_DIR|g" \
-e "s|@POBSYNC_VENV_DIR@|$VENV_DIR|g" \
-e "s|@POBSYNC_ENV_FILE@|$ENV_FILE|g" \
-e "s|@POBSYNC_USER@|$SERVICE_USER|g" \
-e "s|@POBSYNC_GROUP@|$SERVICE_GROUP|g" \
"$src" > "$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