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.
242 lines
6.8 KiB
Bash
Executable File
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
|