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.
Choose Your Production Scope First
Section titled “Choose Your Production Scope First”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.
Prepare for Production
Section titled “Prepare for Production”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_TOKENif you plan to monitor authenticatedGET /api/v1/health(the documented Compose stack uses it;/api/v1/health/liveand/api/v1/health/readydo 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
Why a Reverse Proxy?
Section titled “Why a Reverse Proxy?”A reverse proxy accepts public HTTPS traffic, terminates TLS, and forwards requests to html2rss-web running on your private network.
Option A: Caddy (Automatic HTTPS)
Section titled “Option A: Caddy (Automatic HTTPS)”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
.envfile beside your compose file with the following variables:# Required for reverse proxy and applicationCADDY_HOST=yourdomain.com# Generate with: openssl rand -hex 32HTML2RSS_SECRET_KEY=# Required by the documented Compose stackHEALTH_CHECK_TOKEN=# Required by the default compose stackBROWSERLESS_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
.envbefore starting the stack:- Set
CADDY_HOSTfor your domain. - Generate a production secret (
openssl rand -hex 32) and assign it toHTML2RSS_SECRET_KEY. - Set a strong
HEALTH_CHECK_TOKENwhen you use authenticatedGET /api/v1/health; liveness/readiness probes can use/api/v1/health/liveand/api/v1/health/readywithout it. - Set
BUILD_TAGandGIT_SHAto real release metadata for production. - Adjust optional knobs such as
AUTO_SOURCE_ENABLEDandSENTRY_DSNas needed; refer to the environment reference for details.
- Set
-
After
docker compose up -d, rundocker compose logs caddy --tail 20; look forcertificate obtained. -
Re-test after DNS changes with SSL Labs.
-
Want automatic updates? Add the Watchtower service shown below.
Secure Your Instance
Section titled “Secure Your Instance”Harden the application before inviting other users:
- Set a strong
HEALTH_CHECK_TOKENfor authenticatedGET /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.
Operate & Monitor
Section titled “Operate & Monitor”Keep the instance healthy once it is in production:
- Monitor
https://yourdomain.com/api/v1/healthwith the configured bearer token for authenticated health checks - Review
docker compose logsregularly 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
Auto-update with Watchtower
Section titled “Auto-update with Watchtower”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 caddyThis 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.
Resource Guardrails
Section titled “Resource Guardrails”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.
Share & Support
Section titled “Share & Support”- Test different feed sources before inviting external users
- Publish
/openapi.yamlfrom 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