Skip to main content

One-command Docker deployment to Hetzner VPS

Project description

redock

One command from zero to a live HTTPS app on a Hetzner VPS.

redock up excalidraw --slug drawing

That's it. redock provisions a server, installs Docker and a Caddy reverse proxy, handles DNS, deploys the container, and hands you back a live URL.

How it works

  1. Provision — finds or creates a Hetzner cx22 (or your chosen type)
  2. Prepare — SSHes in, installs Docker + caddy-docker-proxy via Docker Compose
  3. DNS — creates the A record automatically (Hetzner DNS) or prints it for manual entry, then polls until it resolves
  4. Deploy — runs the container with Caddy labels; Caddy gets a Let's Encrypt cert automatically
  5. Verify — polls HTTPS until the app responds 200, then prints the URL

The VPS is shared across deployments — each app is one container behind Caddy.

Prerequisites

  • A Hetzner Cloud account and API token
  • An SSH key uploaded to Hetzner (default name: redock-key)
  • A domain you can add DNS records to
  • Python 3.11+ and uv

For automatic DNS (optional): a Hetzner DNS account with a zone for your domain.

Install

uv pip install redock

Or from source:

git clone https://gitlab.com/toopy/redock
cd redock
uv sync

Configuration

Copy .env.example to .env and fill in the required values:

cp .env.example .env
Variable Required Default Description
REDOCK_HETZNER_TOKEN yes Hetzner Cloud API token
REDOCK_BASE_DOMAIN yes Domain for deployments, e.g. apps.example.com
REDOCK_ACME_EMAIL yes Email for Let's Encrypt notifications
REDOCK_HETZNER_SSH_KEY_NAME no redock-key SSH key name in Hetzner Cloud
REDOCK_SSH_KEY_PATH no ~/.ssh/id_ed25519 Path to local private key
REDOCK_HETZNER_REGION no fsn1 Hetzner datacenter
REDOCK_HETZNER_SERVER_TYPE no cx22 Server type
REDOCK_STATE_FILE no ~/.redock/state.json Where deployment state is stored
REDOCK_CATALOG_DB no ~/.redock/catalog.db Catalog SQLite database path
REDOCK_INFOMANIAK_API_KEY no Required for catalog update --use-ai
REDOCK_INFOMANIAK_PRODUCT_ID no Required for catalog update --use-ai
REDOCK_INFOMANIAK_CHAT_MODEL no google/gemma-4-31B-it LLM model for metadata extraction
REDOCK_DOCKERHUB_USERNAME no Docker Hub username for private image metadata
REDOCK_DOCKERHUB_TOKEN no Docker Hub access token (read-only) for private image metadata
REDOCK_SCAN_TRIVY_WEIGHT no 0.5 Trivy's share of the combined scan score
REDOCK_SCAN_SCOUT_WEIGHT no 0.5 Docker Scout's share of the combined scan score
REDOCK_SCAN_SEV_CRITICAL no 5 Penalty coefficient per CRITICAL vulnerability
REDOCK_SCAN_SEV_HIGH no 2 Penalty coefficient per HIGH vulnerability
REDOCK_SCAN_SEV_MEDIUM no 0.5 Penalty coefficient per MEDIUM vulnerability
REDOCK_SCAN_SEV_LOW no 0.1 Penalty coefficient per LOW vulnerability

Then verify everything looks good:

redock doctor

Automatic DNS with Hetzner DNS

redock uses REDOCK_HETZNER_TOKEN for both VPS provisioning and DNS management. If your domain zone exists in console.hetzner.comNetworking → DNS, redock will create or update the A record automatically on every redock up.

Setup: Add your domain zone in the Hetzner Console and point your registrar's nameservers to Hetzner's — no extra token needed.

Note: redock uses the Hetzner Cloud DNS API (api.hetzner.cloud/v1). The zone must already exist — redock manages records within a zone, not the zone itself. It discovers the right zone by walking the hostname labels (e.g. for drawing.apps.example.com it tries apps.example.com, then example.com).

A real example

Deploy Excalidraw as drawing.apps.example.com:

redock up excalidraw --slug drawing
● Ensuring VPS
● Preparing host (Docker + Caddy)
● DNS records — creating and waiting for propagation
✓ Created DNS A record: drawing.apps.example.com → 65.21.104.33
● Deploying container
● Waiting for HTTPS
✓ Live: https://drawing.apps.example.com

Done! https://drawing.apps.example.com

The --slug flag sets the subdomain prefix. If omitted it defaults to the template name:

redock up <id>                          # → <id>.<base_domain>
redock up <id> -s <slug>               # → <slug>.<base_domain>
redock up <id> --env KEY=VALUE         # override an env var at deploy time
redock up <id> --upgrade               # stop existing container, pull latest image, redeploy

App catalog

# Add an app (all flags optional; Sub-project 2 will fill them via AI)
redock catalog add nginx:latest --port 80
redock catalog add louislam/uptime-kuma:latest --port 3001 --volume /app/data

# Store environment variables on the catalog item (repeatable)
redock catalog add myapp:latest --port 8080 --env DB_URL=postgres://localhost/db --env DEBUG=false
redock catalog update myapp --env SECRET_KEY=abc123   # merges with existing env vars

# Reference a host env var — prefix value with $ (use single quotes to prevent shell expansion)
redock catalog update myapp --env 'DB_PASS=$MY_SECRET'   # stored as-is; resolved at deploy time

# Mark as ready to deploy (or uncheck with --no)
redock catalog check nginx
redock catalog check --no nginx

# List, inspect, update, remove
redock catalog list
redock catalog list --checked-only
redock catalog show nginx
redock catalog update nginx --port 8080
redock catalog delete nginx

# Search the local catalog
redock catalog search ngi

# Scan an image for vulnerabilities (Trivy + Docker Scout)
redock catalog scan nginx
redock catalog scan nginx --dry-run   # scan without saving results
redock catalog scan nginx --verbose   # show per-scanner breakdown

Security scanning

redock catalog scan runs Trivy and Docker Scout against the image, merges their findings, and computes a weighted 0–100 safety score. At least one scanner must be installed — the command skips unavailable scanners gracefully and only fails if none can run.

Install Trivy

task trivy:install

This runs the official install script and places trivy in ~/.local/bin (no sudo needed). Alternatively, install manually:

  • macOS: brew install aquasecurity/trivy/trivy
  • Linux: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b ~/.local/bin

Verify: trivy --version

Install Docker Scout

task scout:install

This installs the Docker Scout CLI plugin to ~/.docker/cli-plugins. Docker Desktop 4.17+ already bundles it — run docker scout version to check before installing.

Verify: docker scout version

Note: redock up requires the template to exist in the catalog and be marked as checked. A missing port also blocks deployment.

Other commands

# See all running deployments
redock list

# Stop a deployment (keeps container and state, can be restarted)
redock stop <slug>

# Remove container + volume + state + DNS record, destroy VPS if no apps remain
redock purge <slug>
redock purge <slug> --yes  # skip confirmation

# VPS - Step-by-step control
redock vps create         # provision VPS only
redock vps install        # install Docker + Caddy only
redock vps show           # print VPS IP and status
redock vps delete         # destroy VPS (blocked if deployments still exist)

# DNS - Step-by-step control
redock dns show <slug>    # print required DNS record
redock dns update <slug>  # create/update A record (Hetzner DNS)
redock dns wait <slug>    # wait until DNS resolves
redock dns clean <slug>   # delete A record (Hetzner DNS)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

redock_vps-0.1.1.tar.gz (90.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

redock_vps-0.1.1-py3-none-any.whl (51.4 kB view details)

Uploaded Python 3

File details

Details for the file redock_vps-0.1.1.tar.gz.

File metadata

  • Download URL: redock_vps-0.1.1.tar.gz
  • Upload date:
  • Size: 90.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for redock_vps-0.1.1.tar.gz
Algorithm Hash digest
SHA256 ca08249a575d78a4e0afb2c5fbd46fa4d5171cf71330e0b3461e4e5080c77c42
MD5 ca544da59d49085980a7cd78180a882a
BLAKE2b-256 472b9bb0ca445846cf4172ec0a57c0a321d05e2ea85c8d08acda23383c9767de

See more details on using hashes here.

File details

Details for the file redock_vps-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: redock_vps-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 51.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for redock_vps-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f859bed0aa52198b02a1d780a4d8647723bd3d34bfa278fbf1907a8e3bb93f37
MD5 b050fa85747e033f8096bc5f67f540a8
BLAKE2b-256 5636cda5ac6bd9c025ef034d8727580238e0d71a40b5aef182afb7af9289b356

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page