# Running Zurg in Hetzner Cloud

Zurg leverages support for .STRM files and WebDAV to create a shareable media library; it pairs very well with Infuse. (This is a low cost, low complexity deployment that is not suited for users of Emby, Jelly, Plex, *arr.)

  • Zurg is available in a private repository: debridmediamanager/zurg
  • Caddy is used as a reverse proxy with automatic SSL certificates to enable HTTPS.
  • Hetzner Cloud Run serves Zurg and Caddy as docker containers in a low-resource virtual server.

# Prerequisites

# Configure Hetzner Cloud Server

  1. Configure Hetzner CLI and your SSH key:

    Create a context for hcloud. You will be prompted for an API token from your Hetzner Cloud project:

     hcloud context create zurg-deployment
     hcloud context active zurg-deployment

    Select the names and ID of an existing SSH key saved to Hetzner Cloud:

     hcloud ssh-key list
     printf "SSH key name or ID: " && read KEY_NAME

    Upload a new public SSH key if needed:

     printf "SSH key name or ID: " && read KEY_NAME
     hcloud ssh-key create --name "$KEY_NAME" --public-key-from-file ~/.ssh/id_rsa.pub
  2. Create a new Hetzner Cloud server:

     hcloud server create \
       --name zurg-server \
       --type cx22 \
       --image ubuntu-22.04 \
       --location fsn1 \
       --ssh-key "$KEY_NAME"

    Once zurg-server is running, save its IP address:

     export ZURG_SERVER_IP=$(hcloud server ip zurg-server)
     echo "Server IP: $ZURG_SERVER_IP"
  3. Update and Install Dependencies:

    Connected to your server:

    local
     hcloud server ssh zurg-server

    Add both Docker and GitHub as package sources to Ubuntu:

    remote
     curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
     | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
     echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
     | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
     curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
     | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
     echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
     | sudo tee /etc/apt/sources.list.d/docker.list

    Install Curl, Docker, Docker Compose version 2, and GitHub CLI:

    remote
     sudo apt update && sudo apt upgrade -y
     sudo apt install -y curl docker.io docker-buildx-plugin docker-compose-plugin gh
  4. Establish GitHub Credentials:

    To access private repositores, your server requires a new or exisiting GitHub Personal Access Token (Classic) with the following scopes: read:packages repo read:org

    Temporarily save your GitHub username and token:

    remote server
     printf "GitHub username: " && read GITHUB_USERNAME
     printf "GitHub token (hidden): " && read -s GITHUB_TOKEN && echo

    Log in to GitHub with both docker and gh

    remote server
     echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_USERNAME" --password-stdin
     echo "$GITHUB_TOKEN" | gh auth login --with-token

    Unset the GITHUB_TOKEN variable after a successful login:

    remote server
     unset GITHUB_TOKEN

# Configure and Deploy Zurg & Caddy

  1. Create a local docker-compose.yml file to define and manage your deployment of Zurg with Caddy for HTTPS:

    docker-compose.yml
    services:
      zurg:
        image: ghcr.io/debridmediamanager/zurg:latest
        command: ["--config", "/app/config.yml"]
        #image: zurg-local
        #command: ["/root/zurg", "--config", "/app/config.yml"]
        container_name: zurg
        restart: always
        expose:
          - "9999"
        volumes:
          - /etc/zurg/config.yml:/app/config.yml:rw
          - /etc/zurg/logs:/app/logs
          - /etc/zurg/data:/app/data
          - /etc/zurg/strm:/app/strm
        environment:
          - LOG_LEVEL=INFO
    
    caddy:
      image: caddy:latest
      container_name: caddy
      restart: always
      ports:
        - "80:80"
        - "443:443"
    
    volumes:
      - /etc/zurg/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    
    volumes:
      caddy_data:
      caddy_config:
  2. Create a local config.yml file for Zurg.

    config.yml
     zurg: v1
     token: ****************************************************
     base_url: "https://username:[email protected]"
     username: ********
     password: ********
     serve_strm_files: true
  3. Create a local Caddyfile for automatic HTTPS:

    Caddyfile
     zurg.andrewe.link {
     	reverse_proxy zurg:9999
     }
  4. Transfer these local files (found in the same folder) to your server :
    docker-compose.yml config.yml Caddyfile

    local
     scp docker-compose.yml config.yml Caddyfile root@$ZURG_SERVER_IP:/tmp/
    remote
     sudo mkdir -p /etc/zurg
     sudo mv /tmp/{docker-compose.yml,config.yml,Caddyfile} /etc/zurg/

    Navigate to the zurg directory, start Zurg in detached mode, and confirm zurg and caddy containers are both running:

    remote
     cd /etc/zurg
     sudo docker compose up -d
     sudo docker ps

# Update Zurg

# option 1: pull latest image recommended

To update Zurg using a pre-built image, update docker-compose.yml, pull :latest image from debridmediamanager/zurg, manually remove any existing zurg containers, and recreate the zurg container in detached mode (apply the update without affecting the Caddy reverse proxy):

docker-compose.yml example
image: ghcr.io/debridmediamanager/zurg:latest
command: ["~/zurg", "--config", "/config/config.yml"]
remote
cd ~
nano docker-compose.yml # optional: edit docker-compose.yml
sudo docker compose pull zurg
sudo docker compose down zurg
sudo docker compose up -d zurg

# option 2: build from source

To update Zurg using the most recent source code, update docker-compose.yml, clone/update debridmediamanager/zurg, rebuild the Docker image, and recreate the container:

docker-compose.yml example
image: zurg-local
command: ["~/zurg", "--config", "/config/config.yml"]
remote
cd ~/zurg
nano docker-compose.yml # optional: edit docker-compose.yml
gh repo clone debridmediamanager/zurg zurg.git
git -C /etc/zurg/zurg.git pull
sudo docker buildx build --no-cache -t zurg-local .
sudo docker compose up -d zurg

# Update Caddy

remote
sudo docker compose pull caddy
sudo docker compose up -d caddy