#
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
- Hetzner Cloud CLI installed and configured.
- GitHub Personal Access Token (Classic) with limited scopes:
read:packagesreporead:org
#
Configure Hetzner Cloud Server
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-deploymentSelect 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_NAMEUpload 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.pubCreate a new Hetzner Cloud server:
hcloud server create \ --name zurg-server \ --type cx22 \ --image ubuntu-22.04 \ --location fsn1 \ --ssh-key "$KEY_NAME"Note
This deployment uses the most basic virtual server
cx22infsn1.Once
zurg-serveris running, save its IP address:export ZURG_SERVER_IP=$(hcloud server ip zurg-server) echo "Server IP: $ZURG_SERVER_IP"Update and Install Dependencies:
Connected to your server:
localhcloud server ssh zurg-serverAdd both Docker and GitHub as package sources to Ubuntu:
remotecurl -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.listInstall Curl, Docker, Docker Compose version 2, and GitHub CLI:
remotesudo apt update && sudo apt upgrade -y sudo apt install -y curl docker.io docker-buildx-plugin docker-compose-plugin ghEstablish GitHub Credentials:
To access private repositores, your server requires a new or exisiting GitHub Personal Access Token (Classic) with the following scopes:
read:packagesreporead:orgTemporarily save your GitHub username and token:
remote serverprintf "GitHub username: " && read GITHUB_USERNAME printf "GitHub token (hidden): " && read -s GITHUB_TOKEN && echoLog in to GitHub with both
dockerandghremote serverecho "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_USERNAME" --password-stdin echo "$GITHUB_TOKEN" | gh auth login --with-tokenUnset the
GITHUB_TOKENvariable after a successful login:remote serverunset GITHUB_TOKENWarning
Ensure this token is limited in scope:
reporead:packagesread:orgThe token will still be exposed in these files:
/root/.docker/config.json
~/.config/gh/hosts.yml.
#
Configure and Deploy Zurg & Caddy
Create a local
docker-compose.ymlfile to define and manage your deployment of Zurg with Caddy for HTTPS:docker-compose.ymlservices: 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:Create a local
config.ymlfile for Zurg.config.ymlzurg: v1 token: **************************************************** base_url: "https://username:password@your.domain.org" username: ******** password: ******** serve_strm_files: trueCreate a local
Caddyfilefor automatic HTTPS:Caddyfilezurg.andrewe.link { reverse_proxy zurg:9999 }Transfer these local files (found in the same folder) to your server :
docker-compose.ymlconfig.ymlCaddyfilelocalscp docker-compose.yml config.yml Caddyfile root@$ZURG_SERVER_IP:/tmp/remotesudo mkdir -p /etc/zurg sudo mv /tmp/{docker-compose.yml,config.yml,Caddyfile} /etc/zurg/Navigate to the
zurgdirectory, start Zurg in detached mode, and confirmzurgandcaddycontainers are both running:remotecd /etc/zurg sudo docker compose up -d sudo docker psNote
This command will pull the
:latestZurg and Caddy images, start both containers, and make Zurg accessible via HTTPS (automatic SSL certificates).
#
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):
image: ghcr.io/debridmediamanager/zurg:latest
command: ["~/zurg", "--config", "/config/config.yml"]
Important
The locally built image will use ~/zurg as the binary path and the location of your config.yml file. Update docker-compose.yml accordingly.
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:
image: zurg-local
command: ["~/zurg", "--config", "/config/config.yml"]
Important
The locally built image will use ~/zurg as the binary path and the location of your config.yml file. Update docker-compose.yml accordingly.
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
sudo docker compose pull caddy
sudo docker compose up -d caddy
Tip
Caddy automatically handles SSL certificate provisioning and renewal through Let’s Encrypt. No manual certificate management is required. Certificates are stored in the caddy_data Docker volume and will be automatically renewed before expiration.