Add a Django updater view for checking configured Gitea releases, inspecting the installed git checkout, fetching tags, pulling the current branch, and running the configured native systemd update command. Document the updater environment settings and keep the page staff-only so readonly status users cannot trigger deployment actions.
599 lines
18 KiB
Bash
Executable File
599 lines
18 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}
|
|
BACKUP_ROOT_EXPLICIT=0
|
|
if [ -n "${POBSYNC_BACKUP_ROOT:-}" ]; then
|
|
BACKUP_ROOT_EXPLICIT=1
|
|
fi
|
|
WEB_BIND=${POBSYNC_WEB_BIND:-127.0.0.1:8010}
|
|
TIME_ZONE=${POBSYNC_TIME_ZONE:-}
|
|
FORCE_ENV=0
|
|
INSTALL_OS_PACKAGES=1
|
|
WITH_NGINX=0
|
|
VERBOSE=0
|
|
INTERACTIVE=0
|
|
CREATE_SUPERUSER=ask
|
|
SUPERUSER_USERNAME=${POBSYNC_SUPERUSER_USERNAME:-}
|
|
SUPERUSER_EMAIL=${POBSYNC_SUPERUSER_EMAIL:-}
|
|
SUPERUSER_PASSWORD=${POBSYNC_SUPERUSER_PASSWORD:-}
|
|
|
|
if [ -t 0 ]; then
|
|
INTERACTIVE=1
|
|
fi
|
|
|
|
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
|
|
BACKUP_ROOT_EXPLICIT=1
|
|
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
|
|
;;
|
|
--time-zone)
|
|
TIME_ZONE=$2
|
|
shift 2
|
|
;;
|
|
--force-env)
|
|
FORCE_ENV=1
|
|
shift
|
|
;;
|
|
--verbose)
|
|
VERBOSE=1
|
|
shift
|
|
;;
|
|
--interactive)
|
|
INTERACTIVE=1
|
|
shift
|
|
;;
|
|
--non-interactive)
|
|
INTERACTIVE=0
|
|
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
|
|
;;
|
|
--create-superuser)
|
|
CREATE_SUPERUSER=1
|
|
shift
|
|
;;
|
|
--no-create-superuser)
|
|
CREATE_SUPERUSER=0
|
|
shift
|
|
;;
|
|
--superuser-username)
|
|
SUPERUSER_USERNAME=$2
|
|
shift 2
|
|
;;
|
|
--superuser-email)
|
|
SUPERUSER_EMAIL=$2
|
|
shift 2
|
|
;;
|
|
--superuser-password)
|
|
SUPERUSER_PASSWORD=$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
|
|
|
|
if [ -f "$ENV_FILE" ] && [ "$FORCE_ENV" -ne 1 ] && [ "$BACKUP_ROOT_EXPLICIT" -ne 1 ]; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "$ENV_FILE"
|
|
set +a
|
|
if [ -n "${POBSYNC_BACKUP_ROOT:-}" ]; then
|
|
BACKUP_ROOT=$POBSYNC_BACKUP_ROOT
|
|
fi
|
|
fi
|
|
|
|
detect_time_zone() {
|
|
if [ -n "$TIME_ZONE" ]; then
|
|
printf '%s\n' "$TIME_ZONE"
|
|
return
|
|
fi
|
|
|
|
if [ -n "${POBSYNC_TIME_ZONE:-}" ]; then
|
|
printf '%s\n' "$POBSYNC_TIME_ZONE"
|
|
return
|
|
fi
|
|
|
|
if command -v timedatectl >/dev/null 2>&1; then
|
|
detected=$(timedatectl show -p Timezone --value 2>/dev/null || true)
|
|
if [ -n "$detected" ]; then
|
|
printf '%s\n' "$detected"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
if [ -f /etc/timezone ]; then
|
|
detected=$(sed -n '1p' /etc/timezone | tr -d '[:space:]')
|
|
if [ -n "$detected" ]; then
|
|
printf '%s\n' "$detected"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
printf 'UTC\n'
|
|
}
|
|
|
|
TIME_ZONE=$(detect_time_zone)
|
|
|
|
run_step() {
|
|
label=$1
|
|
shift
|
|
|
|
if [ "$VERBOSE" -eq 1 ]; then
|
|
echo "==> $label"
|
|
"$@"
|
|
echo "OK: $label"
|
|
return
|
|
fi
|
|
|
|
printf '%-48s' "$label"
|
|
log_file=$(mktemp)
|
|
if "$@" >"$log_file" 2>&1; then
|
|
rm -f "$log_file"
|
|
echo "OK"
|
|
return
|
|
fi
|
|
|
|
echo "FAILED"
|
|
echo
|
|
echo "Output from failed step '$label':" >&2
|
|
cat "$log_file" >&2
|
|
rm -f "$log_file"
|
|
exit 1
|
|
}
|
|
|
|
note_step() {
|
|
label=$1
|
|
status=$2
|
|
printf '%-48s%s\n' "$label" "$status"
|
|
}
|
|
|
|
prompt_value() {
|
|
prompt=$1
|
|
default=$2
|
|
if [ "$INTERACTIVE" -ne 1 ]; then
|
|
printf '%s\n' "$default"
|
|
return
|
|
fi
|
|
|
|
printf '%s [%s]: ' "$prompt" "$default" >&2
|
|
read -r answer
|
|
if [ -n "$answer" ]; then
|
|
printf '%s\n' "$answer"
|
|
else
|
|
printf '%s\n' "$default"
|
|
fi
|
|
}
|
|
|
|
prompt_yes_no() {
|
|
prompt=$1
|
|
default=$2
|
|
if [ "$INTERACTIVE" -ne 1 ]; then
|
|
printf '%s\n' "$default"
|
|
return
|
|
fi
|
|
|
|
if [ "$default" -eq 1 ]; then
|
|
suffix=Y/n
|
|
else
|
|
suffix=y/N
|
|
fi
|
|
|
|
while :; do
|
|
printf '%s [%s]: ' "$prompt" "$suffix" >&2
|
|
read -r answer
|
|
case "$answer" in
|
|
"")
|
|
printf '%s\n' "$default"
|
|
return
|
|
;;
|
|
y|Y|yes|YES|Yes)
|
|
printf '1\n'
|
|
return
|
|
;;
|
|
n|N|no|NO|No)
|
|
printf '0\n'
|
|
return
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
prompt_secret() {
|
|
prompt=$1
|
|
if [ "$INTERACTIVE" -ne 1 ]; then
|
|
printf '\n'
|
|
return
|
|
fi
|
|
|
|
printf '%s: ' "$prompt" >&2
|
|
stty -echo
|
|
read -r secret
|
|
stty echo
|
|
printf '\n' >&2
|
|
printf '%s\n' "$secret"
|
|
}
|
|
|
|
if [ "$INTERACTIVE" -eq 1 ]; then
|
|
echo "pobsync native installer"
|
|
echo
|
|
echo "Press Enter to accept defaults. Existing command-line flags are already applied as defaults."
|
|
echo
|
|
|
|
SOURCE_DIR=$(prompt_value "Source checkout" "$SOURCE_DIR")
|
|
APP_DIR=$(prompt_value "Install app directory" "$APP_DIR")
|
|
VENV_DIR=$(prompt_value "Python virtualenv directory" "$VENV_DIR")
|
|
ENV_FILE=$(prompt_value "Environment file" "$ENV_FILE")
|
|
SERVICE_USER=$(prompt_value "Service user" "$SERVICE_USER")
|
|
SERVICE_GROUP=$(prompt_value "Service group" "$SERVICE_GROUP")
|
|
BACKUP_ROOT=$(prompt_value "Backup storage path" "$BACKUP_ROOT")
|
|
WEB_BIND=$(prompt_value "Gunicorn bind address" "$WEB_BIND")
|
|
TIME_ZONE=$(prompt_value "Scheduler time zone" "$TIME_ZONE")
|
|
ALLOWED_HOSTS=$(prompt_value "Allowed hosts" "$ALLOWED_HOSTS")
|
|
CSRF_TRUSTED_ORIGINS=$(prompt_value "CSRF trusted origins, comma-separated or blank" "$CSRF_TRUSTED_ORIGINS")
|
|
INSTALL_OS_PACKAGES=$(prompt_yes_no "Install required OS packages with apt-get" "$INSTALL_OS_PACKAGES")
|
|
|
|
use_mariadb=0
|
|
if [ "$INSTALL_EXTRAS" = "mariadb" ] || [ "$INSTALL_EXTRAS" = "[mariadb]" ] || [ "$INSTALL_EXTRAS" = ".[mariadb]" ]; then
|
|
use_mariadb=1
|
|
fi
|
|
use_mariadb=$(prompt_yes_no "Install MariaDB Python/client support" "$use_mariadb")
|
|
if [ "$use_mariadb" -eq 1 ]; then
|
|
INSTALL_EXTRAS=mariadb
|
|
else
|
|
INSTALL_EXTRAS=
|
|
fi
|
|
|
|
WITH_NGINX=$(prompt_yes_no "Install starter nginx reverse proxy config" "$WITH_NGINX")
|
|
if [ "$WITH_NGINX" -eq 1 ]; then
|
|
SERVER_NAME=$(prompt_value "Nginx server_name" "$SERVER_NAME")
|
|
fi
|
|
|
|
if [ "$CREATE_SUPERUSER" = "ask" ]; then
|
|
CREATE_SUPERUSER=$(prompt_yes_no "Create first Django superuser after install" 1)
|
|
fi
|
|
if [ "$CREATE_SUPERUSER" -eq 1 ]; then
|
|
SUPERUSER_USERNAME=$(prompt_value "Superuser username" "${SUPERUSER_USERNAME:-admin}")
|
|
SUPERUSER_EMAIL=$(prompt_value "Superuser email, blank allowed" "$SUPERUSER_EMAIL")
|
|
if [ -z "$SUPERUSER_PASSWORD" ]; then
|
|
SUPERUSER_PASSWORD=$(prompt_secret "Superuser password, leave blank to run createsuperuser interactively later")
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
fi
|
|
|
|
if [ "$CREATE_SUPERUSER" = "ask" ]; then
|
|
if [ -n "$SUPERUSER_USERNAME" ] && [ -n "$SUPERUSER_PASSWORD" ]; then
|
|
CREATE_SUPERUSER=1
|
|
else
|
|
CREATE_SUPERUSER=0
|
|
fi
|
|
fi
|
|
|
|
install_os_packages() {
|
|
if [ "$INSTALL_OS_PACKAGES" -ne 1 ]; then
|
|
note_step "Install OS packages" "SKIPPED"
|
|
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
|
|
run_step "Install OS packages" sh -c "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 ! env POBSYNC_INSTALL_TIME_ZONE="$TIME_ZONE" python3 -c "import os; from zoneinfo import ZoneInfo; ZoneInfo(os.environ['POBSYNC_INSTALL_TIME_ZONE'])" >/dev/null 2>&1; then
|
|
echo "Invalid time zone: $TIME_ZONE" >&2
|
|
echo "Use an IANA timezone such as UTC or Europe/Amsterdam." >&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
|
|
run_step "Create service group" groupadd --system "$SERVICE_GROUP"
|
|
else
|
|
note_step "Create service group" "OK"
|
|
fi
|
|
|
|
if ! id "$SERVICE_USER" >/dev/null 2>&1; then
|
|
run_step "Create service user" useradd --system --home /var/lib/pobsync --shell /usr/sbin/nologin --gid "$SERVICE_GROUP" "$SERVICE_USER"
|
|
else
|
|
note_step "Create service user" "OK"
|
|
fi
|
|
|
|
grant_journal_access() {
|
|
for group in systemd-journal adm; do
|
|
if getent group "$group" >/dev/null 2>&1; then
|
|
usermod -a -G "$group" "$SERVICE_USER"
|
|
fi
|
|
done
|
|
}
|
|
|
|
run_step "Grant journal access" grant_journal_access
|
|
run_step "Prepare directories" mkdir -p /etc/pobsync /var/lib/pobsync /var/log/pobsync "$(dirname "$VENV_DIR")" "$APP_DIR" "$BACKUP_ROOT"
|
|
run_step "Set state directory permissions" chown "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync "$BACKUP_ROOT"
|
|
run_step "Set private directory modes" chmod 0750 /var/lib/pobsync /var/log/pobsync "$BACKUP_ROOT"
|
|
|
|
if [ "$SOURCE_DIR" != "$APP_DIR" ]; then
|
|
run_step "Sync application files" rsync -a --delete \
|
|
--exclude .git \
|
|
--exclude .venv \
|
|
--exclude __pycache__ \
|
|
--exclude .pytest_cache \
|
|
--exclude .mypy_cache \
|
|
--exclude var \
|
|
"$SOURCE_DIR"/ "$APP_DIR"/
|
|
else
|
|
note_step "Sync application files" "SKIPPED"
|
|
fi
|
|
|
|
run_step "Create Python virtualenv" python3 -m venv "$VENV_DIR"
|
|
run_step "Upgrade pip" "$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
|
|
run_step "Install Python package" "$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_TIME_ZONE=$TIME_ZONE
|
|
POBSYNC_SQLITE_PATH=/var/lib/pobsync/pobsync.sqlite3
|
|
POBSYNC_STATIC_ROOT=/var/lib/pobsync/static
|
|
POBSYNC_ENV_FILE=$ENV_FILE
|
|
POBSYNC_SERVICE_USER=$SERVICE_USER
|
|
POBSYNC_SERVICE_GROUP=$SERVICE_GROUP
|
|
|
|
POBSYNC_WEB_BIND=$WEB_BIND
|
|
POBSYNC_GUNICORN_WORKERS=2
|
|
POBSYNC_GUNICORN_TIMEOUT=120
|
|
POBSYNC_WORKER_INTERVAL=15
|
|
POBSYNC_SCHEDULER_INTERVAL=60
|
|
POBSYNC_UPDATE_RELEASES_URL=
|
|
POBSYNC_UPDATE_RELEASES_TOKEN=
|
|
POBSYNC_UPDATE_GIT_REMOTE=origin
|
|
POBSYNC_UPDATE_COMMAND=sudo -n scripts/update-systemd
|
|
EOF
|
|
chmod 0640 "$ENV_FILE"
|
|
chown "root:$SERVICE_GROUP" "$ENV_FILE"
|
|
note_step "Write environment file" "OK"
|
|
else
|
|
note_step "Write environment file" "SKIPPED"
|
|
echo "Keeping existing $ENV_FILE. Use --force-env to rewrite it."
|
|
fi
|
|
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "$ENV_FILE"
|
|
set +a
|
|
|
|
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_units() {
|
|
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
|
|
}
|
|
|
|
run_step "Install systemd units" install_units
|
|
|
|
install_manage_wrapper() {
|
|
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" \
|
|
"$APP_DIR/deploy/bin/pobsync-manage" > /usr/local/bin/pobsync-manage
|
|
chmod 0755 /usr/local/bin/pobsync-manage
|
|
}
|
|
|
|
run_step "Install manage wrapper" install_manage_wrapper
|
|
|
|
run_step "Reload systemd" systemctl daemon-reload
|
|
run_step "Run database migrations" /usr/local/bin/pobsync-manage migrate --noinput
|
|
run_step "Ensure default SSH key" /usr/local/bin/pobsync-manage ensure_pobsync_ssh_key --name default --set-global-default
|
|
run_step "Collect static files" /usr/local/bin/pobsync-manage collectstatic --noinput --clear
|
|
run_step "Finalize state permissions" chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync
|
|
|
|
superuser_exists=$("$VENV_DIR/bin/python" -c "import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pobsync_server.settings'); import django; django.setup(); from django.contrib.auth import get_user_model; print('yes' if get_user_model().objects.filter(is_superuser=True).exists() else 'no')")
|
|
if [ "$CREATE_SUPERUSER" -eq 1 ]; then
|
|
if [ "$superuser_exists" = "yes" ]; then
|
|
note_step "Create Django superuser" "SKIPPED"
|
|
elif [ -n "$SUPERUSER_USERNAME" ] && [ -n "$SUPERUSER_PASSWORD" ]; then
|
|
run_step "Create Django superuser" env \
|
|
DJANGO_SUPERUSER_USERNAME="$SUPERUSER_USERNAME" \
|
|
DJANGO_SUPERUSER_EMAIL="$SUPERUSER_EMAIL" \
|
|
DJANGO_SUPERUSER_PASSWORD="$SUPERUSER_PASSWORD" \
|
|
/usr/local/bin/pobsync-manage createsuperuser --noinput
|
|
run_step "Finalize superuser permissions" chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync
|
|
else
|
|
note_step "Create Django superuser" "SKIPPED"
|
|
echo "No superuser password was provided; create one later with:"
|
|
echo " sudo -u $SERVICE_USER pobsync-manage createsuperuser"
|
|
fi
|
|
elif [ "$superuser_exists" != "yes" ]; then
|
|
note_step "Create Django superuser" "SKIPPED"
|
|
echo "No Django superuser exists yet. Create one with:"
|
|
echo " sudo -u $SERVICE_USER pobsync-manage createsuperuser"
|
|
else
|
|
note_step "Create Django superuser" "SKIPPED"
|
|
fi
|
|
|
|
run_step "Enable services" systemctl enable pobsync-web.service pobsync-worker.service pobsync-scheduler.service
|
|
run_step "Restart services" systemctl restart pobsync-web.service pobsync-worker.service pobsync-scheduler.service
|
|
|
|
if [ "$WITH_NGINX" -eq 1 ]; then
|
|
if ! command -v nginx >/dev/null 2>&1; then
|
|
note_step "Install nginx config" "SKIPPED"
|
|
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
|
|
note_step "Install nginx config" "OK"
|
|
run_step "Validate nginx config" nginx -t
|
|
run_step "Reload nginx" systemctl reload nginx
|
|
fi
|
|
else
|
|
note_step "Install nginx config" "SKIPPED"
|
|
fi
|
|
|
|
if [ "$VERBOSE" -eq 1 ]; then
|
|
systemctl --no-pager --full status pobsync-web.service pobsync-worker.service pobsync-scheduler.service || true
|
|
fi
|
|
|
|
echo
|
|
echo "pobsync installation complete."
|
|
echo
|
|
echo "Open the Django control panel at:"
|
|
echo " http://$WEB_BIND/"
|
|
echo
|
|
echo "If pobsync is behind a reverse proxy, use your public hostname instead."
|
|
echo
|
|
echo "Recommended first steps:"
|
|
echo " 1. Log in to the Django control panel."
|
|
echo " 2. Open Self Check and resolve any warnings."
|
|
echo " 3. Configure global settings and backup storage."
|
|
echo " 4. Add an SSH key under SSH Keys."
|
|
echo " 5. Add a host and queue a dry-run backup."
|
|
echo
|
|
echo "Useful commands:"
|
|
echo " systemctl status pobsync-web pobsync-worker pobsync-scheduler"
|
|
echo " journalctl -u pobsync-worker -f"
|
|
echo " sudo -u $SERVICE_USER pobsync-manage check"
|
|
echo " sudo -u $SERVICE_USER pobsync-manage check_pobsync_install"
|