Skip to content

Deployment & Production

html2rss-web ships on Docker Hub, so you can launch this self-hosted service wherever Docker runs. Start with the official docker-compose.yml as your baseline, and treat the Getting Started guide as the required first proof that your instance can already serve included feeds locally.

If you have not yet created a local instance, complete the Getting Started guide first. It walks through the one-time project directory setup, creating a minimal compose file, and confirming the application locally, which gives you the right baseline before exposing a self-hosted instance publicly.

Already running html2rss-web on your workstation? The sections below focus on what changes when you take that setup to production.

There are two materially different deployment modes:

  • Included feeds only: lowest-maintenance path, suitable when the packaged feed set already covers your needs
  • Included feeds plus automatic generation: requires AUTO_SOURCE_ENABLED=true, bearer-token distribution, and Browserless capacity planning

If you do not need page-URL generation yet, keep AUTO_SOURCE_ENABLED off and ship the simpler mode first.

Before exposing html2rss-web, ensure:

  • Your domain (for example yourdomain.com) resolves to the host running Docker
  • Inbound TCP ports 80 and 443 reach the host (check firewalls and cloud security groups)
  • You are ready to watch the first deployment logs for certificate issuance
  • You have a value ready for HTML2RSS_SECRET_KEY
  • You have a value ready for HEALTH_CHECK_TOKEN if you plan to monitor authenticated GET /api/v1/health (the documented Compose stack uses it; /api/v1/health/live and /api/v1/health/ready do not require it)

If you plan to enable automatic feed generation, also prepare:

  • BROWSERLESS_IO_API_TOKEN
  • Browserless capacity appropriate for the sites you expect to render
  • an operator plan for how users obtain valid bearer tokens

A reverse proxy accepts public HTTPS traffic, terminates TLS, and forwards requests to html2rss-web running on your private network.

Caddy handles certificates and redirects with almost no configuration.

services:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- caddy_data:/data
command:
- caddy
- reverse-proxy
- --from
- ${CADDY_HOST}
- --to
- html2rss-web:4000
html2rss-web:
image: html2rss/web:latest
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
RACK_ENV: production
PORT: 4000
BUILD_TAG: ${BUILD_TAG:-local}
GIT_SHA: ${GIT_SHA:-local}
HTML2RSS_SECRET_KEY: ${HTML2RSS_SECRET_KEY:?set HTML2RSS_SECRET_KEY}
HEALTH_CHECK_TOKEN: ${HEALTH_CHECK_TOKEN:?set HEALTH_CHECK_TOKEN}
SENTRY_DSN: ${SENTRY_DSN:-}
BROWSERLESS_IO_WEBSOCKET_URL: ws://browserless:4002
BROWSERLESS_IO_API_TOKEN: ${BROWSERLESS_IO_API_TOKEN:?set BROWSERLESS_IO_API_TOKEN}
browserless:
image: "ghcr.io/browserless/chromium"
restart: unless-stopped
environment:
PORT: 4002
CONCURRENT: 10
TOKEN: ${BROWSERLESS_IO_API_TOKEN:?set BROWSERLESS_IO_API_TOKEN}
volumes:
caddy_data:
  • Create a .env file beside your compose file with the following variables:

    # Required for reverse proxy and application
    CADDY_HOST=yourdomain.com
    # Generate with: openssl rand -hex 32
    HTML2RSS_SECRET_KEY=
    # Required by the documented Compose stack
    HEALTH_CHECK_TOKEN=
    # Required by the default compose stack
    BROWSERLESS_IO_API_TOKEN=
    # Recommended for production traceability (compose defaults to local)
    BUILD_TAG=
    # Recommended for production traceability (compose defaults to local)
    GIT_SHA=
  • Update your .env before starting the stack:

    • Set CADDY_HOST for your domain.
    • Generate a production secret (openssl rand -hex 32) and assign it to HTML2RSS_SECRET_KEY.
    • Set a strong HEALTH_CHECK_TOKEN when you use authenticated GET /api/v1/health; liveness/readiness probes can use /api/v1/health/live and /api/v1/health/ready without it.
    • Set BUILD_TAG and GIT_SHA to real release metadata for production.
    • Adjust optional knobs such as AUTO_SOURCE_ENABLED and SENTRY_DSN as needed; refer to the environment reference for details.
  • After docker compose up -d, run docker compose logs caddy --tail 20; look for certificate obtained.

  • Re-test after DNS changes with SSL Labs.

  • Want automatic updates? Add the Watchtower service shown below.

Harden the application before inviting other users:

  • Set a strong HEALTH_CHECK_TOKEN for authenticated GET /api/v1/health, and separate strong bearer tokens for any protected feeds
  • Prefer environment files (.env) stored outside version control for secrets
  • Keep any operator-only token distribution flow outside public docs and outside version control
services:
html2rss-web:
image: html2rss/web:latest
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
RACK_ENV: production
PORT: 4000
BUILD_TAG: ${BUILD_TAG:-local}
GIT_SHA: ${GIT_SHA:-local}
HTML2RSS_SECRET_KEY: ${HTML2RSS_SECRET_KEY:?set HTML2RSS_SECRET_KEY}
HEALTH_CHECK_TOKEN: ${HEALTH_CHECK_TOKEN:?set HEALTH_CHECK_TOKEN}
SENTRY_DSN: ${SENTRY_DSN:-}
BROWSERLESS_IO_WEBSOCKET_URL: ws://browserless:4002
BROWSERLESS_IO_API_TOKEN: ${BROWSERLESS_IO_API_TOKEN:?set BROWSERLESS_IO_API_TOKEN}
browserless:
image: "ghcr.io/browserless/chromium"
restart: unless-stopped
environment:
PORT: 4002
CONCURRENT: 10
TOKEN: ${BROWSERLESS_IO_API_TOKEN:?set BROWSERLESS_IO_API_TOKEN}

Store these variables in a .env file and reference it with env_file: as demonstrated in the Caddy example.

Keep the instance healthy once it is in production:

  • Monitor https://yourdomain.com/api/v1/health with the configured bearer token for authenticated health checks
  • Review docker compose logs regularly for feed errors or certificate renewals
  • Enable automatic image updates so security patches roll out quickly
  • Right-size CPU and memory to avoid starvation when parsing large feeds
services:
watchtower:
image: containrrr/watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# Optional for private registries only:
# - "${HOME}/.docker/config.json:/config.json:ro"
command: --cleanup --interval 7200 html2rss-web browserless caddy

This Watchtower shape scopes updates to html2rss-web, browserless, and caddy; replace service names if your stack differs.

Check docker compose logs watchtower occasionally to confirm updates are applied.

services:
html2rss-web:
image: html2rss/web:latest
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
reservations:
memory: 256M
cpus: "0.25"

Adjust the limits to match your host capacity. Increase memory if you process many large feeds.

  • Test different feed sources before inviting external users
  • Publish /openapi.yaml from the running instance if you expect agents or integrations to call the API directly
  • Add your instance to the community wiki if you want it listed publicly
  • Visit the troubleshooting guide or join the community discussions when you need help
  • Ready to contribute fixes or docs? See the contributing guide