diff --git a/README.md b/README.md index fb37af1c..534f8a4c 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,9 @@ docker run -d \ | Use Case | File | Description | | --------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -| **All-in-One Deployment** | [docker-compose-aio.yml](docker/docker-compose.aio.yml) | ⭐ Recommended! A simple, all-in-one solution — everything runs in a single container for quick setup. | +| **All-in-One Deployment** | [docker-compose.aio.yml](docker/docker-compose.aio.yml) | ⭐ Recommended! A simple, all-in-one solution — everything runs in a single container for quick setup. | | **Modular Deployment** | [docker-compose.yml](docker/docker-compose.yml) | Separate containers for Dispatcharr, Celery, and Postgres — perfect if you want more granular control. | -| **Development Environment** | [docker-compose-dev.yml](docker/docker-compose.dev.yml) | Developer-friendly setup with pre-configured ports and settings for contributing and testing. | +| **Development Environment** | [docker-compose.dev.yml](docker/docker-compose.dev.yml) | Developer-friendly setup with pre-configured ports and settings for contributing and testing. | --- @@ -133,4 +133,4 @@ Have a question? Want to suggest a feature? Just want to say hi?\ --- -### 🚀 *Happy Streaming! The Dispatcharr Team* +### 🚀 *Happy Streaming! The Dispatcharr Team* \ No newline at end of file diff --git a/debian_install.sh b/debian_install.sh new file mode 100644 index 00000000..0e41139e --- /dev/null +++ b/debian_install.sh @@ -0,0 +1,413 @@ +#!/usr/bin/env bash + +set -e + +############################################################################## +# 0) Warning / Disclaimer +############################################################################## + +echo "**************************************************************" +echo "WARNING: While we do not anticipate any problems, we disclaim all" +echo "responsibility for anything that happens to your machine." +echo "" +echo "This script is intended for **Debian-based operating systems only**." +echo "Running it on other distributions WILL cause unexpected issues." +echo "" +echo "This script is **NOT RECOMMENDED** for use on your primary machine." +echo "For safety and best results, we strongly advise running this inside a" +echo "clean virtual machine (VM) or LXC container environment." +echo "" +echo "Additionally, there is NO SUPPORT for this method; Docker is the only" +echo "officially supported way to run Dispatcharr." +echo "**************************************************************" +echo "" +echo "If you wish to proceed, type \"I understand\" and press Enter." +read user_input + +if [ "$user_input" != "I understand" ]; then + echo "Exiting script..." + exit 1 +fi + + +############################################################################## +# 1) Configuration +############################################################################## + +# Linux user/group under which Dispatcharr processes will run +DISPATCH_USER="dispatcharr" +DISPATCH_GROUP="dispatcharr" + +# Where Dispatcharr source code should live +APP_DIR="/opt/dispatcharr" + +# Git branch to clone (e.g., "main" or "dev") +DISPATCH_BRANCH="dev" + +# PostgreSQL settings +POSTGRES_DB="dispatcharr" +POSTGRES_USER="dispatch" +POSTGRES_PASSWORD="secret" + +# The port on which Nginx will listen for HTTP +NGINX_HTTP_PORT="9191" + +# The TCP port for Daphné (Django Channels) +WEBSOCKET_PORT="8001" + +# Directory inside /run/ for our socket; full path becomes /run/dispatcharr/dispatcharr.sock +GUNICORN_RUNTIME_DIR="dispatcharr" +GUNICORN_SOCKET="/run/${GUNICORN_RUNTIME_DIR}/dispatcharr.sock" + +############################################################################## +# 2) Install System Packages +############################################################################## + +echo ">>> Installing system packages..." +apt-get update +apt-get install -y \ + git \ + curl \ + wget \ + build-essential \ + gcc \ + libpcre3-dev \ + libpq-dev \ + python3-dev \ + python3-venv \ + python3-pip \ + nginx \ + redis-server \ + postgresql \ + postgresql-contrib \ + ffmpeg \ + procps \ + streamlink + +# Node.js setup (v23.x from NodeSource) - adjust version if needed +if ! command -v node >/dev/null 2>&1; then + echo ">>> Installing Node.js..." + curl -sL https://deb.nodesource.com/setup_23.x | bash - + apt-get install -y nodejs +fi + +# Start & enable PostgreSQL and Redis +systemctl enable postgresql redis-server +systemctl start postgresql redis-server + +############################################################################## +# 3) Create Dispatcharr User/Group +############################################################################## + +if ! getent group "${DISPATCH_GROUP}" >/dev/null; then + echo ">>> Creating group: ${DISPATCH_GROUP}" + groupadd "${DISPATCH_GROUP}" +fi + +if ! id -u "${DISPATCH_USER}" >/dev/null; then + echo ">>> Creating user: ${DISPATCH_USER}" + useradd -m -g "${DISPATCH_GROUP}" -s /bin/bash "${DISPATCH_USER}" +fi + +############################################################################## +# 4) Configure PostgreSQL Database +############################################################################## + +echo ">>> Configuring PostgreSQL..." +su - postgres -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='${POSTGRES_DB}'\"" | grep -q 1 || \ + su - postgres -c "psql -c \"CREATE DATABASE ${POSTGRES_DB};\"" + +su - postgres -c "psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='${POSTGRES_USER}'\"" | grep -q 1 || \ + su - postgres -c "psql -c \"CREATE USER ${POSTGRES_USER} WITH PASSWORD '${POSTGRES_PASSWORD}';\"" + +su - postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_USER};\"" +su - postgres -c "psql -c \"ALTER DATABASE ${POSTGRES_DB} OWNER TO ${POSTGRES_USER};\"" +su - postgres -c "psql -d ${POSTGRES_DB} -c \"ALTER SCHEMA public OWNER TO ${POSTGRES_USER};\"" + +############################################################################## +# 5) Clone or Update Dispatcharr Code +############################################################################## + +echo ">>> Installing or updating Dispatcharr in ${APP_DIR} ..." + +if [ ! -d "${APP_DIR}" ]; then + echo ">>> Cloning repository for the first time..." + mkdir -p "${APP_DIR}" + chown "${DISPATCH_USER}:${DISPATCH_GROUP}" "${APP_DIR}" + su - "${DISPATCH_USER}" -c "git clone -b ${DISPATCH_BRANCH} https://github.com/Dispatcharr/Dispatcharr.git ${APP_DIR}" +else + echo ">>> Updating existing repository..." + su - "${DISPATCH_USER}" <>> Setting up Python virtual environment..." +su - "${DISPATCH_USER}" <>> Linking ffmpeg into the virtual environment..." +ln -sf /usr/bin/ffmpeg ${APP_DIR}/env/bin/ffmpeg + +############################################################################## +# 7) Build Frontend (React) +############################################################################## + +echo ">>> Building frontend..." +su - "${DISPATCH_USER}" <>> Running Django migrations & collectstatic..." +su - "${DISPATCH_USER}" </etc/systemd/system/dispatcharr.service +[Unit] +Description=Gunicorn for Dispatcharr +After=network.target postgresql.service redis-server.service + +[Service] +User=${DISPATCH_USER} +Group=${DISPATCH_GROUP} +WorkingDirectory=${APP_DIR} + +RuntimeDirectory=${GUNICORN_RUNTIME_DIR} +RuntimeDirectoryMode=0775 + +# Update PATH to include both the virtualenv and system binaries (for ffmpeg) +Environment="PATH=${APP_DIR}/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" +Environment="POSTGRES_DB=${POSTGRES_DB}" +Environment="POSTGRES_USER=${POSTGRES_USER}" +Environment="POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" +Environment="POSTGRES_HOST=localhost" + +ExecStart=${APP_DIR}/env/bin/gunicorn \\ + --workers=4 \\ + --worker-class=gevent \\ + --timeout=300 \\ + --bind unix:${GUNICORN_SOCKET} \\ + dispatcharr.wsgi:application + +Restart=always +KillMode=mixed + +[Install] +WantedBy=multi-user.target +EOF + +############################################################################## +# 10) Create Systemd Service for Celery +############################################################################## + +cat </etc/systemd/system/dispatcharr-celery.service +[Unit] +Description=Celery Worker for Dispatcharr +After=network.target redis-server.service +Requires=dispatcharr.service + +[Service] +User=${DISPATCH_USER} +Group=${DISPATCH_GROUP} +WorkingDirectory=${APP_DIR} +Environment="PATH=${APP_DIR}/env/bin" +Environment="POSTGRES_DB=${POSTGRES_DB}" +Environment="POSTGRES_USER=${POSTGRES_USER}" +Environment="POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" +Environment="POSTGRES_HOST=localhost" +Environment="CELERY_BROKER_URL=redis://localhost:6379/0" + +ExecStart=${APP_DIR}/env/bin/celery -A dispatcharr worker -l info + +Restart=always +KillMode=mixed + +[Install] +WantedBy=multi-user.target +EOF + +############################################################################## +# 11) Create Systemd Service for Celery Beat (Optional) +############################################################################## + +cat </etc/systemd/system/dispatcharr-celerybeat.service +[Unit] +Description=Celery Beat Scheduler for Dispatcharr +After=network.target redis-server.service +Requires=dispatcharr.service + +[Service] +User=${DISPATCH_USER} +Group=${DISPATCH_GROUP} +WorkingDirectory=${APP_DIR} +Environment="PATH=${APP_DIR}/env/bin" +Environment="POSTGRES_DB=${POSTGRES_DB}" +Environment="POSTGRES_USER=${POSTGRES_USER}" +Environment="POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" +Environment="POSTGRES_HOST=localhost" +Environment="CELERY_BROKER_URL=redis://localhost:6379/0" + +ExecStart=${APP_DIR}/env/bin/celery -A dispatcharr beat -l info + +Restart=always +KillMode=mixed + +[Install] +WantedBy=multi-user.target +EOF + +############################################################################## +# 12) Create Systemd Service for Daphné (WebSockets / Channels) +############################################################################## + +cat </etc/systemd/system/dispatcharr-daphne.service +[Unit] +Description=Daphne for Dispatcharr (ASGI) +After=network.target +Requires=dispatcharr.service + +[Service] +User=${DISPATCH_USER} +Group=${DISPATCH_GROUP} +WorkingDirectory=${APP_DIR} +Environment="PATH=${APP_DIR}/env/bin" +Environment="POSTGRES_DB=${POSTGRES_DB}" +Environment="POSTGRES_USER=${POSTGRES_USER}" +Environment="POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" +Environment="POSTGRES_HOST=localhost" + +ExecStart=${APP_DIR}/env/bin/daphne -b 0.0.0.0 -p ${WEBSOCKET_PORT} dispatcharr.asgi:application + +Restart=always +KillMode=mixed + +[Install] +WantedBy=multi-user.target +EOF + +############################################################################## +# 13) Configure Nginx +############################################################################## + +echo ">>> Configuring Nginx at /etc/nginx/sites-available/dispatcharr.conf ..." +cat </etc/nginx/sites-available/dispatcharr.conf +server { + listen ${NGINX_HTTP_PORT}; + + # Proxy to Gunicorn socket for main HTTP traffic + location / { + include proxy_params; + proxy_pass http://unix:${GUNICORN_SOCKET}; + } + + # Serve Django static files + location /static/ { + alias ${APP_DIR}/static/; + } + + # Serve React build assets + location /assets/ { + alias ${APP_DIR}/frontend/dist/assets/; + } + + # Serve media files if any + location /media/ { + alias ${APP_DIR}/media/; + } + + # WebSockets for Daphné + location /ws/ { + proxy_pass http://127.0.0.1:${WEBSOCKET_PORT}; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header Host \$host; + } +} +EOF + +ln -sf /etc/nginx/sites-available/dispatcharr.conf /etc/nginx/sites-enabled/dispatcharr.conf + +# Remove default site if it exists +if [ -f /etc/nginx/sites-enabled/default ]; then + rm -f /etc/nginx/sites-enabled/default +fi + +echo ">>> Testing Nginx config..." +nginx -t + +echo ">>> Restarting Nginx..." +systemctl restart nginx +systemctl enable nginx + +############################################################################## +# 14) Start & Enable Services +############################################################################## + +echo ">>> Enabling systemd services..." +systemctl daemon-reload +systemctl enable dispatcharr +systemctl enable dispatcharr-celery +systemctl enable dispatcharr-celerybeat +systemctl enable dispatcharr-daphne + +echo ">>> Restarting / Starting services..." +systemctl restart dispatcharr +systemctl restart dispatcharr-celery +systemctl restart dispatcharr-celerybeat +systemctl restart dispatcharr-daphne + +############################################################################## +# Done! +############################################################################## + +echo "=================================================" +echo "Dispatcharr installation (or update) complete!" +echo "Nginx is listening on port ${NGINX_HTTP_PORT}." +echo "Gunicorn socket: ${GUNICORN_SOCKET}." +echo "WebSockets on port ${WEBSOCKET_PORT} (path /ws/)." +echo "You can check logs via 'sudo journalctl -u dispatcharr -f', etc." +echo "Visit http://:${NGINX_HTTP_PORT} in your browser." +echo "================================================="