mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-24 18:48:36 +00:00
feat(debian_install): switch from Gunicorn to uWSGI and update installation script
This commit is contained in:
parent
d388f45137
commit
2196660aec
2 changed files with 50 additions and 31 deletions
|
|
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Changed
|
||||
|
||||
- **`debian_install.sh` switched from Gunicorn to uWSGI with gevent workers.** The Debian/LXC bare-metal installer now deploys Dispatcharr under the same uWSGI + gevent stack used by the Docker image, eliminating a class of compatibility differences between the two deployment paths. The installer writes a `uwsgi-debian.ini` next to the app and manages uWSGI via a systemd service. The nginx site config now uses `uwsgi_pass` + `include uwsgi_params` instead of `proxy_pass`, which correctly populates `SERVER_PORT` in the WSGI environ so M3U playlist URLs include the configured port number (fixing the port-stripping bug from #1267 for bare-metal installs). Python 3.13 is now provisioned through uv's managed runtime so the install works on Debian 12 and Ubuntu 24.04 LTS regardless of the system Python version.
|
||||
- **`get_vod_streams` XC API response was missing metadata fields available from basic sync.** When a provider includes `director`, `cast`, `release_date`, `plot`, `genre`, or `year` in its `get_vod_streams` response, Dispatcharr stores those fields during the basic sync pass but was not including them in its own `get_vod_streams` XC output. The endpoint now outputs all six fields. The `trailer` key in the response also mapped to the wrong internal key (`trailer` instead of `youtube_trailer`) following the storage key rename, so the trailer field was always empty until an advanced refresh ran. Both issues are corrected. Users with existing libraries should trigger a VOD provider refresh to populate the missing fields. (Fixes #1228)
|
||||
- **Docker base image now uses a multi-stage build.** The builder stage installs compilers and dev headers (`gcc`, `g++`, `gfortran`, `build-essential`, `libopenblas-dev`, `libpcre3-dev`, `python3.13-dev`, `ninja-build`) to create the virtual environment and compile the legacy NumPy wheel (cpu-baseline=none for old hardware). The final runtime image starts from the same ffmpeg base, copies only the prebuilt venv and wheel from the builder, and installs only the runtime libraries needed at runtime - eliminating compiler binaries from production containers and reducing final image size. — Thanks [@kensac](https://github.com/kensac)
|
||||
- **`libpq-dev` removed from both build and runtime stages.** The project uses `psycopg[binary]` (psycopg3), which bundles its own statically linked copy of libpq inside the wheel. No system libpq headers or shared library are needed at build or runtime.
|
||||
|
|
|
|||
|
|
@ -64,11 +64,9 @@ configure_variables() {
|
|||
POSTGRES_PASSWORD="secret"
|
||||
NGINX_HTTP_PORT="9191"
|
||||
WEBSOCKET_PORT="8001"
|
||||
GUNICORN_RUNTIME_DIR="dispatcharr"
|
||||
GUNICORN_SOCKET="/run/${GUNICORN_RUNTIME_DIR}/dispatcharr.sock"
|
||||
PYTHON_BIN=$(command -v python3)
|
||||
UWSGI_RUNTIME_DIR="dispatcharr"
|
||||
UWSGI_SOCKET="/run/${UWSGI_RUNTIME_DIR}/dispatcharr.sock"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
NGINX_SITE="/etc/nginx/sites-available/dispatcharr"
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
|
@ -79,8 +77,8 @@ install_packages() {
|
|||
echo ">>> Installing system packages..."
|
||||
apt-get update
|
||||
declare -a packages=(
|
||||
git curl wget build-essential gcc libpq-dev
|
||||
python3-dev python3-venv python3-pip nginx redis-server
|
||||
git curl wget build-essential gcc libpq-dev libpcre3-dev
|
||||
nginx redis-server
|
||||
postgresql postgresql-contrib ffmpeg procps streamlink
|
||||
sudo
|
||||
)
|
||||
|
|
@ -113,6 +111,11 @@ create_dispatcharr_user() {
|
|||
##############################################################################
|
||||
|
||||
setup_postgresql() {
|
||||
echo ">>> Waiting for PostgreSQL to accept connections..."
|
||||
until pg_isready -h /var/run/postgresql >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo ">>> Checking PostgreSQL database and user..."
|
||||
|
||||
db_exists=$(sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$POSTGRES_DB'")
|
||||
|
|
@ -143,7 +146,7 @@ setup_postgresql() {
|
|||
|
||||
clone_dispatcharr_repo() {
|
||||
echo ">>> Installing or updating Dispatcharr in ${APP_DIR} ..."
|
||||
|
||||
|
||||
if [ ! -d "$APP_DIR" ]; then
|
||||
mkdir -p "$APP_DIR"
|
||||
chown "$DISPATCH_USER:$DISPATCH_GROUP" "$APP_DIR"
|
||||
|
|
@ -171,14 +174,8 @@ EOSU
|
|||
# 6) Setup Python Environment
|
||||
##############################################################################
|
||||
|
||||
install_uv() {
|
||||
echo ">>> Installing UV package manager..."
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
}
|
||||
|
||||
setup_python_env() {
|
||||
echo ">>> Setting up Python virtual environment with UV..."
|
||||
echo ">>> Setting up Python virtual environment with UV (Python 3.13)..."
|
||||
|
||||
su - "$DISPATCH_USER" <<EOSU
|
||||
set -euo pipefail
|
||||
|
|
@ -188,13 +185,12 @@ setup_python_env() {
|
|||
command -v uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
rm -rf env
|
||||
$PYTHON_BIN -m venv env
|
||||
env/bin/python -m ensurepip --upgrade
|
||||
# uv creates the venv with a managed Python 3.13 (auto-downloads if missing),
|
||||
# avoiding system Python version mismatches on Debian 12 / Ubuntu 24.04.
|
||||
uv venv --python 3.13 env
|
||||
|
||||
export UV_PROJECT_ENVIRONMENT="$APP_DIR/env"
|
||||
uv sync --no-dev
|
||||
|
||||
env/bin/python -m pip install -q gunicorn
|
||||
EOSU
|
||||
|
||||
ln -sf /usr/bin/ffmpeg "$APP_DIR/env/bin/ffmpeg"
|
||||
|
|
@ -291,17 +287,40 @@ EOSU
|
|||
configure_services() {
|
||||
echo ">>> Creating systemd service files..."
|
||||
|
||||
# Gunicorn
|
||||
# uWSGI config
|
||||
cat <<EOF >${APP_DIR}/uwsgi-debian.ini
|
||||
[uwsgi]
|
||||
chdir = ${APP_DIR}
|
||||
module = dispatcharr.wsgi:application
|
||||
virtualenv = ${APP_DIR}/env
|
||||
master = true
|
||||
workers = 4
|
||||
socket = ${UWSGI_SOCKET}
|
||||
chmod-socket = 666
|
||||
vacuum = true
|
||||
die-on-term = true
|
||||
gevent = 100
|
||||
gevent-early-monkey-patch = true
|
||||
import = dispatcharr.gevent_patch
|
||||
lazy-apps = true
|
||||
buffer-size = 65536
|
||||
socket-timeout = 600
|
||||
thunder-lock = true
|
||||
EOF
|
||||
|
||||
chown ${DISPATCH_USER}:${DISPATCH_GROUP} ${APP_DIR}/uwsgi-debian.ini
|
||||
|
||||
# uWSGI
|
||||
cat <<EOF >${SYSTEMD_DIR}/dispatcharr.service
|
||||
[Unit]
|
||||
Description=Gunicorn for Dispatcharr
|
||||
Description=uWSGI for Dispatcharr
|
||||
After=network.target postgresql.service redis-server.service
|
||||
|
||||
[Service]
|
||||
User=${DISPATCH_USER}
|
||||
Group=${DISPATCH_GROUP}
|
||||
WorkingDirectory=${APP_DIR}
|
||||
RuntimeDirectory=${GUNICORN_RUNTIME_DIR}
|
||||
RuntimeDirectory=${UWSGI_RUNTIME_DIR}
|
||||
RuntimeDirectoryMode=0775
|
||||
EnvironmentFile=/opt/dispatcharr/.env
|
||||
Environment="PATH=${APP_DIR}/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
|
||||
|
|
@ -310,12 +329,7 @@ Environment="POSTGRES_USER=${POSTGRES_USER}"
|
|||
Environment="POSTGRES_PASSWORD=${POSTGRES_PASSWORD}"
|
||||
Environment="POSTGRES_HOST=localhost"
|
||||
ExecStartPre=/usr/bin/bash -c 'until pg_isready -h localhost -U ${POSTGRES_USER}; do sleep 1; done'
|
||||
ExecStart=${APP_DIR}/env/bin/gunicorn \\
|
||||
--workers=4 \\
|
||||
--worker-class=gevent \\
|
||||
--timeout=300 \\
|
||||
--bind unix:${GUNICORN_SOCKET} \\
|
||||
dispatcharr.wsgi:application
|
||||
ExecStart=${APP_DIR}/env/bin/uwsgi --ini ${APP_DIR}/uwsgi-debian.ini
|
||||
Restart=always
|
||||
KillMode=mixed
|
||||
SyslogIdentifier=dispatcharr
|
||||
|
|
@ -412,10 +426,14 @@ EOF
|
|||
cat <<EOF >/etc/nginx/sites-available/dispatcharr.conf
|
||||
server {
|
||||
listen ${NGINX_HTTP_PORT};
|
||||
client_max_body_size 0;
|
||||
|
||||
location / {
|
||||
include proxy_params;
|
||||
proxy_set_header X-Forwarded-Port \$server_port;
|
||||
proxy_pass http://unix:${GUNICORN_SOCKET};
|
||||
include uwsgi_params;
|
||||
uwsgi_param HTTP_X_REAL_IP \$remote_addr;
|
||||
uwsgi_read_timeout 600;
|
||||
uwsgi_send_timeout 600;
|
||||
uwsgi_pass unix:${UWSGI_SOCKET};
|
||||
}
|
||||
location /static/ {
|
||||
alias ${APP_DIR}/static/;
|
||||
|
|
@ -466,7 +484,7 @@ show_summary() {
|
|||
=================================================
|
||||
Dispatcharr installation (or update) complete!
|
||||
Nginx is listening on port ${NGINX_HTTP_PORT}.
|
||||
Gunicorn socket: ${GUNICORN_SOCKET}.
|
||||
uWSGI socket: ${UWSGI_SOCKET}.
|
||||
WebSockets on port ${WEBSOCKET_PORT} (path /ws/).
|
||||
|
||||
You can check logs via:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue