Refactor Dispatcharr install script for uv and systemd

Switches Python environment setup and package installation to use uv, updates PostgreSQL version to 17, and streamlines database credential creation. Replaces direct systemd ExecStart commands with wrapper scripts for Gunicorn, Celery, Celery Beat, and Daphne, and updates systemd service files for improved reliability. Adds extra proxy headers to Nginx config and improves overall script structure and messaging.
This commit is contained in:
CanbiZ 2025-10-20 11:04:20 +02:00
parent 071f2aa83a
commit 5ad3e3043b

View File

@ -17,7 +17,6 @@ msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
build-essential \ build-essential \
gcc \ gcc \
libpcre3-dev \
libpq-dev \ libpq-dev \
nginx \ nginx \
redis-server \ redis-server \
@ -26,11 +25,11 @@ $STD apt install -y \
streamlink streamlink
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PYTHON_VERSION="3.13" setup_uv setup_uv
NODE_VERSION="22" setup_nodejs NODE_VERSION="22" setup_nodejs
PG_VERSION="16" setup_postgresql PG_VERSION="17" setup_postgresql
msg_info "Set up PostgreSQL Database" msg_info "Creating PostgreSQL Database"
DB_NAME=dispatcharr_db DB_NAME=dispatcharr_db
DB_USER=dispatcharr_usr DB_USER=dispatcharr_usr
DB_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)" DB_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
@ -39,59 +38,34 @@ $STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCO
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';" $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';" $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';" $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
{
echo "Dispatcharr-Credentials" cat <<EOF >~/dispatcharr.creds
echo "Dispatcharr Database Name: $DB_NAME" Dispatcharr-Credentials
echo "Dispatcharr Database User: $DB_USER" Dispatcharr Database Name: $DB_NAME
echo "Dispatcharr Database Password: $DB_PASS" Dispatcharr Database User: $DB_USER
} >>~/dispatcharr.creds Dispatcharr Database Password: $DB_PASS
msg_ok "Set up PostgreSQL Database" EOF
msg_ok "Created PostgreSQL Database"
fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr" fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr"
msg_info "Setup Python virtual environment" msg_info "Configuring Dispatcharr"
cd /opt/dispatcharr cd /opt/dispatcharr || exit
# uv venv erstellt ein minimales venv - wir nutzen uv zum Installieren
$STD uv venv env
msg_ok "Virtual environment created"
msg_info "Installing Python requirements" $STD uv sync --frozen
PYPI_URL="https://pypi.org/simple" $STD uv run --frozen python manage.py migrate --noinput
mapfile -t EXTRA_INDEX_URLS < <(grep -E '^(--(extra-)?index-url|-i)\s' requirements.txt 2>/dev/null | awk '{print $2}' | sed 's#/*$##') $STD uv run --frozen python manage.py collectstatic --noinput
UV_INDEX_ARGS=(--index-url "$PYPI_URL" --index-strategy unsafe-best-match) cd /opt/dispatcharr/frontend || exit
for u in "${EXTRA_INDEX_URLS[@]}"; do
[[ -n "$u" && "$u" != "$PYPI_URL" ]] && UV_INDEX_ARGS+=(--extra-index-url "$u")
done
if [[ -f requirements.txt ]]; then
$STD uv pip install --python /opt/dispatcharr/env/bin/python "${UV_INDEX_ARGS[@]}" -r requirements.txt
fi
$STD uv pip install --python /opt/dispatcharr/env/bin/python "${UV_INDEX_ARGS[@]}" gunicorn gevent celery daphne
ln -sf /usr/bin/ffmpeg /opt/dispatcharr/env/bin/ffmpeg
msg_ok "Python Requirements Installed"
msg_info "Building Frontend"
cd /opt/dispatcharr/frontend
$STD npm install --legacy-peer-deps $STD npm install --legacy-peer-deps
$STD npm run build $STD npm run build
msg_ok "Built Frontend" msg_ok "Configured Dispatcharr"
msg_info "Running Django Migrations"
cd /opt/dispatcharr
export POSTGRES_DB="$DB_NAME"
export POSTGRES_USER="$DB_USER"
export POSTGRES_PASSWORD="$DB_PASS"
export POSTGRES_HOST="localhost"
$STD ./env/bin/python manage.py migrate --noinput
$STD ./env/bin/python manage.py collectstatic --noinput
msg_ok "Migrations Complete"
msg_info "Configuring Nginx" msg_info "Configuring Nginx"
cat <<EOF >/etc/nginx/sites-available/dispatcharr.conf cat <<EOF >/etc/nginx/sites-available/dispatcharr.conf
server { server {
listen 9191; listen 9191;
server_name _;
location / { location / {
include proxy_params; include proxy_params;
@ -116,6 +90,9 @@ server {
proxy_set_header Upgrade \$http_upgrade; proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "Upgrade"; proxy_set_header Connection "Upgrade";
proxy_set_header Host \$host; proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
} }
} }
EOF EOF
@ -123,34 +100,74 @@ EOF
ln -sf /etc/nginx/sites-available/dispatcharr.conf /etc/nginx/sites-enabled/dispatcharr.conf ln -sf /etc/nginx/sites-available/dispatcharr.conf /etc/nginx/sites-enabled/dispatcharr.conf
rm -f /etc/nginx/sites-enabled/default rm -f /etc/nginx/sites-enabled/default
$STD nginx -t $STD nginx -t
systemctl restart nginx systemctl enable -q --now nginx
systemctl enable nginx
msg_ok "Configured Nginx" msg_ok "Configured Nginx"
msg_info "Creating systemd services" msg_info "Creating Services"
cat <<EOF >/opt/dispatcharr/start-gunicorn.sh
#!/usr/bin/env bash
cd /opt/dispatcharr
export POSTGRES_DB=$DB_NAME
export POSTGRES_USER=$DB_USER
export POSTGRES_PASSWORD=$DB_PASS
export POSTGRES_HOST=localhost
uv run --frozen gunicorn \
--workers=4 \
--worker-class=gevent \
--timeout=300 \
--bind 0.0.0.0:5656 \
dispatcharr.wsgi:application
EOF
chmod +x /opt/dispatcharr/start-gunicorn.sh
cat <<EOF >/opt/dispatcharr/start-celery.sh
#!/usr/bin/env bash
cd /opt/dispatcharr
export POSTGRES_DB=$DB_NAME
export POSTGRES_USER=$DB_USER
export POSTGRES_PASSWORD=$DB_PASS
export POSTGRES_HOST=localhost
export CELERY_BROKER_URL=redis://localhost:6379/0
uv run --frozen celery -A dispatcharr worker -l info -c 4
EOF
chmod +x /opt/dispatcharr/start-celery.sh
cat <<EOF >/opt/dispatcharr/start-celerybeat.sh
#!/usr/bin/env bash
cd /opt/dispatcharr
export POSTGRES_DB=$DB_NAME
export POSTGRES_USER=$DB_USER
export POSTGRES_PASSWORD=$DB_PASS
export POSTGRES_HOST=localhost
export CELERY_BROKER_URL=redis://localhost:6379/0
uv run --frozen celery -A dispatcharr beat -l info
EOF
chmod +x /opt/dispatcharr/start-celerybeat.sh
cat <<EOF >/opt/dispatcharr/start-daphne.sh
#!/usr/bin/env bash
cd /opt/dispatcharr
export POSTGRES_DB=$DB_NAME
export POSTGRES_USER=$DB_USER
export POSTGRES_PASSWORD=$DB_PASS
export POSTGRES_HOST=localhost
uv run --frozen daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application
EOF
chmod +x /opt/dispatcharr/start-daphne.sh
cat <<EOF >/etc/systemd/system/dispatcharr.service cat <<EOF >/etc/systemd/system/dispatcharr.service
[Unit] [Unit]
Description=Gunicorn for Dispatcharr Description=Dispatcharr Web Server
After=network.target postgresql.service redis-server.service After=network.target postgresql.service redis-server.service
[Service] [Service]
Type=simple
WorkingDirectory=/opt/dispatcharr WorkingDirectory=/opt/dispatcharr
RuntimeDirectory=dispatcharr ExecStart=/opt/dispatcharr/start-gunicorn.sh
RuntimeDirectoryMode=0775 Restart=on-failure
Environment="PATH=/opt/dispatcharr/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" RestartSec=10
Environment="POSTGRES_DB=$DB_NAME" User=root
Environment="POSTGRES_USER=$DB_USER"
Environment="POSTGRES_PASSWORD=$DB_PASS"
Environment="POSTGRES_HOST=localhost"
ExecStart=/opt/dispatcharr/env/bin/gunicorn \\
--workers=4 \\
--worker-class=gevent \\
--timeout=300 \\
--bind 0.0.0.0:5656 \\
dispatcharr.wsgi:application
Restart=always
KillMode=mixed
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -158,21 +175,17 @@ EOF
cat <<EOF >/etc/systemd/system/dispatcharr-celery.service cat <<EOF >/etc/systemd/system/dispatcharr-celery.service
[Unit] [Unit]
Description=Celery Worker for Dispatcharr Description=Dispatcharr Celery Worker
After=network.target redis-server.service After=network.target redis-server.service
Requires=dispatcharr.service Requires=dispatcharr.service
[Service] [Service]
Type=simple
WorkingDirectory=/opt/dispatcharr WorkingDirectory=/opt/dispatcharr
Environment="PATH=/opt/dispatcharr/env/bin" ExecStart=/opt/dispatcharr/start-celery.sh
Environment="POSTGRES_DB=$DB_NAME" Restart=on-failure
Environment="POSTGRES_USER=$DB_USER" RestartSec=10
Environment="POSTGRES_PASSWORD=$DB_PASS" User=root
Environment="POSTGRES_HOST=localhost"
Environment="CELERY_BROKER_URL=redis://localhost:6379/0"
ExecStart=/opt/dispatcharr/env/bin/celery -A dispatcharr worker -l info -c 4
Restart=always
KillMode=mixed
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -180,21 +193,17 @@ EOF
cat <<EOF >/etc/systemd/system/dispatcharr-celerybeat.service cat <<EOF >/etc/systemd/system/dispatcharr-celerybeat.service
[Unit] [Unit]
Description=Celery Beat Scheduler for Dispatcharr Description=Dispatcharr Celery Beat Scheduler
After=network.target redis-server.service After=network.target redis-server.service
Requires=dispatcharr.service Requires=dispatcharr.service
[Service] [Service]
Type=simple
WorkingDirectory=/opt/dispatcharr WorkingDirectory=/opt/dispatcharr
Environment="PATH=/opt/dispatcharr/env/bin" ExecStart=/opt/dispatcharr/start-celerybeat.sh
Environment="POSTGRES_DB=$DB_NAME" Restart=on-failure
Environment="POSTGRES_USER=$DB_USER" RestartSec=10
Environment="POSTGRES_PASSWORD=$DB_PASS" User=root
Environment="POSTGRES_HOST=localhost"
Environment="CELERY_BROKER_URL=redis://localhost:6379/0"
ExecStart=/opt/dispatcharr/env/bin/celery -A dispatcharr beat -l info
Restart=always
KillMode=mixed
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -202,28 +211,25 @@ EOF
cat <<EOF >/etc/systemd/system/dispatcharr-daphne.service cat <<EOF >/etc/systemd/system/dispatcharr-daphne.service
[Unit] [Unit]
Description=Daphne for Dispatcharr (ASGI) Description=Dispatcharr WebSocket Server (Daphne)
After=network.target After=network.target
Requires=dispatcharr.service Requires=dispatcharr.service
[Service] [Service]
Type=simple
WorkingDirectory=/opt/dispatcharr WorkingDirectory=/opt/dispatcharr
Environment="PATH=/opt/dispatcharr/env/bin" ExecStart=/opt/dispatcharr/start-daphne.sh
Environment="POSTGRES_DB=$DB_NAME" Restart=on-failure
Environment="POSTGRES_USER=$DB_USER" RestartSec=10
Environment="POSTGRES_PASSWORD=$DB_PASS" User=root
Environment="POSTGRES_HOST=localhost"
ExecStart=/opt/dispatcharr/env/bin/daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application
Restart=always
KillMode=mixed
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl enable --now dispatcharr dispatcharr-celery dispatcharr-celerybeat dispatcharr-daphne systemctl enable -q --now dispatcharr dispatcharr-celery dispatcharr-celerybeat dispatcharr-daphne
msg_ok "Started Dispatcharr Services" msg_ok "Created Services"
motd_ssh motd_ssh
customize customize