Skip to content

Deployment & Production

html2rss-web ships on Docker Hub. Start with the Getting Started guide, then add the production pieces below.

The examples use html2rss/web:1, the recommended major-version tag. Pin an exact release if your deployment process requires it.

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 terminates public HTTPS traffic and forwards requests to html2rss-web on your private Docker network.

Caddy handles certificates and redirects.

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:1
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
RACK_ENV: production
PORT: 4000
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}
BOTASAURUS_SCRAPER_URL: http://botasaurus:4010
botasaurus:
image: html2rss/botasaurus-scrape-api:latest
restart: unless-stopped
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:

CADDY_HOST=yourdomain.com
HTML2RSS_SECRET_KEY=<openssl rand -hex 32>
HEALTH_CHECK_TOKEN=<strong bearer token>
BROWSERLESS_IO_API_TOKEN=<browserless token>

Before starting the stack:

  • Set CADDY_HOST for your domain.
  • Generate HTML2RSS_SECRET_KEY with openssl rand -hex 32.
  • 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.
  • Leave BUILD_TAG and GIT_SHA unset unless you intentionally override image metadata in logs.
  • 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.

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:1
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
RACK_ENV: production
PORT: 4000
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}
BOTASAURUS_SCRAPER_URL: http://botasaurus:4010
botasaurus:
image: html2rss/botasaurus-scrape-api:latest
restart: unless-stopped
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 for the Docker tag you selected
  • 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 botasaurus browserless caddy

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

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

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

Adjust limits to match host capacity. Increase memory for 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