Configuration
RSSMonster has sensible defaults for a personal installation, but database, crawling, security, AI, and recommendation behavior can be configured with environment variables.
Where Configuration Lives
The configuration file depends on how RSSMonster is run:
- Default Docker Compose: create
.envin the repository root. Compose reads it for variable substitution indocker-compose.yml. - MySQL Docker Compose: use the same root
.envwithdocker-compose.mysql.yml. - Manual server installation: copy
server/.env.exampletoserver/.env. The web process and crawl worker both load this file. - Client: copy
client/.env.exampletoclient/.env. Variables beginning withVITE_are compiled into the client bundle, so rebuild the client after changing them.
Restart the affected process or recreate its container after changing server settings. For Docker, only variables listed under the service’s environment section are passed into the container. To use an additional server option, add it to that section, for example:
services:
rssmonster:
environment:
CRAWL_VERBOSE_LOGGING: ${CRAWL_VERBOSE_LOGGING:-false}
Do not commit .env files. Store secrets as long, random values and restrict access to them.
Docker Configuration
The supplied Compose files accept these root .env values:
| Variable | Default | Description |
|---|---|---|
RSSMONSTER_TAG | latest | RSSMonster image tag to run. |
RSSMONSTER_PORT | 3000 | Host port mapped to container port 3000. |
JWT_SECRET | required | Secret used to sign login tokens. |
FEVER_CREDENTIAL_SECRET | required | Secret used to protect Fever API credentials. Keep it stable after users create credentials. |
TRUST_PROXY | loopback | Express trusted-proxy setting; see Proxy and network security. |
RSSMONSTER_INTERNAL_HOST_ALLOWLIST | empty | Explicit exceptions for feeds hosted on private networks. |
The MySQL Compose file additionally accepts:
| Variable | Default | Description |
|---|---|---|
DB_DATABASE | rssmonster | MySQL database name. |
DB_USERNAME | rssmonster | MySQL application user. |
DB_PASSWORD | required | Password shared by RSSMonster and the MySQL application user. |
MYSQL_ROOT_PASSWORD | required | MySQL root password used by the database container. |
Generate secrets with openssl rand -hex 32. Use a different value for each secret and password.
Database
SQLite
DB_DIALECT=sqlite
DB_STORAGE=./data/rssmonster.sqlite
DB_STORAGE is resolved relative to the server directory for a manual installation. Use an absolute path in production when that makes persistence clearer. The default Docker deployment sets it to /app/data/rssmonster.sqlite and mounts a persistent volume at /app/data.
RSSMonster enables WAL mode, foreign-key enforcement, and a five-second busy timeout for SQLite. It also forces sequential crawling: parallel feed processing is disabled, concurrent user crawls are limited to one, and the user batch size is limited to one. Settings that request more concurrency are therefore ignored or capped when SQLite is active.
MySQL
DB_DIALECT=mysql
DB_HOSTNAME=localhost
DB_PORT=3306
DB_DATABASE=rssmonster
DB_USERNAME=rssmonster
DB_PASSWORD=replace-with-a-strong-password
Use MySQL for higher write concurrency, multiple active users, or more demanding workloads. All five connection values are required when DB_DIALECT=mysql; the default port is 3306.
After changing databases or creating a new database, apply the canonical migrations from the server directory with npm run db. Docker images apply pending migrations automatically at startup.
Application and Authentication
| Variable | Default | Description |
|---|---|---|
NODE_ENV | development | Runtime mode: development, production, or test. Use production for deployments. |
PORT | 3000 | HTTP port used by the server. The supplied containers set this to 3000. |
JWT_SECRET | none | Required secret for signing and verifying JWTs. |
JWT_EXPIRES_IN | 86400 | Login-token lifetime in seconds. The example file uses 604800 (seven days). |
FEVER_CREDENTIAL_SECRET | none | Required secret for keyed Fever credential hashes. Changing it invalidates existing Fever API credentials. |
ENABLE_DEVELOPMENT_LOGIN | false | Enables login without normal credentials, but only when NODE_ENV=development. Never enable it in a shared environment. |
DEVELOPMENT_LOGIN_USER_ID | none | Existing positive user ID selected by development login. It must be set when development login is enabled. |
ENABLE_HTTPS | false | When true, starts the server with certificates from server/cert. A reverse proxy is usually easier to operate. |
DISABLE_LISTENER | false | Prevents the HTTP listener from starting. This is intended for one-off crawl commands and tests. |
Authentication and API credential flows require these secrets. The supplied Compose files refuse to start without them. Keep both values stable across restarts and upgrades.
See First Login for the normal registration flow and the security implications of enabling development login.
Feed Crawling and Scheduling
Most installations should begin with the example defaults. Increase concurrency gradually while watching database load, crawl duration, HTTP 429 responses, and timeouts.
| Variable | Default | Unit | Effect |
|---|---|---|---|
FEED_MAX_COUNT | 10 | feeds | Maximum feeds claimed by one crawl invocation. |
FEED_PARALLEL_CONCURRENCY | 3 | feeds | Process-wide simultaneous feed workers. SQLite caps this at 1. |
FEED_TIMEOUT_MS | 60000 | ms | Overall processing deadline for one feed. |
FEED_LEASE_MS | 120000 | ms | Duration of a feed claim. The effective value is never less than twice FEED_TIMEOUT_MS. |
CRAWL_TIMEOUT_MS | 600000 | ms | Overall deadline for a crawl invocation. |
CRAWL_DUPLICATE_CACHE_DAYS | 30 | days | Article history loaded into the deterministic duplicate cache. Higher values use more memory and database work. |
CRAWL_RUN_MAX_RUNNING_MINUTES | 60 | minutes | Age after which an unfinished crawl run is marked stale. |
CRAWL_PARALLELPROCESSFLAG | 0 | boolean integer | Set to 1 to allow parallel feed processing on MySQL. SQLite always forces 0. |
CRAWL_WORKER_INTERVAL_MS | 60000 | ms | Delay between dedicated worker polls. Must be a positive integer. |
CRAWL_VERBOSE_LOGGING | false | boolean | Emits candidate, retry, and feed-discovery diagnostics in addition to final results. |
FEED_PARALLEL_CONCURRENCY is the main MySQL throughput control. Raising it increases simultaneous network, parser, AI, and database work. Keep FEED_LEASE_MS comfortably above realistic feed-processing time so another worker does not reclaim active work.
HTTP Fetch Behavior
| Variable | Default | Unit | Effect |
|---|---|---|---|
FEED_HTTP_TIMEOUT_MS | 10000 | ms | Deadline for an individual feed HTTP request. |
FEED_RESPONSE_MAX_BYTES | 10485760 | bytes | Maximum downloaded response body (10 MiB). |
FEED_ORIGIN_MAX_CONCURRENCY | 2 | requests | Simultaneous requests to the same origin. |
FEED_ORIGIN_MIN_SPACING_MS | 250 | ms | Minimum delay between requests to the same origin. Set to 0 to disable spacing. |
FEED_CACHE_FRESHNESS_MAX_MS | 86400000 | ms | Maximum accepted cache-freshness period from publisher headers (one day). |
FEED_RETRY_AFTER_MAX_MS | 604800000 | ms | Maximum accepted Retry-After delay (seven days). |
Lower per-origin concurrency and larger spacing are gentler on publishers. Increasing response or timeout limits can accommodate unusual feeds, but also increases the resources a slow or oversized response may consume.
Parser Safety Limits
Feeds are parsed in disposable worker threads with CPU and memory bounds. Entries that exceed the configured input limits are rejected before article enrichment and persistence.
| Variable | Default | Unit | Effect |
|---|---|---|---|
FEED_PARSER_TIMEOUT_MS | 2000 | ms | Parser worker deadline. |
FEED_PARSER_MEMORY_MB | 64 | MiB | Parser worker old-generation heap limit. |
FEED_MAX_ENTRIES | 1000 | entries | Maximum entries accepted in one feed response. |
FEED_MAX_GUID_BYTES | 4096 | bytes | Maximum normalized entry identifier size. |
FEED_MAX_URL_BYTES | 8192 | bytes | Maximum normalized entry URL size. |
FEED_MAX_TITLE_BYTES | 4096 | bytes | Maximum normalized title size. |
FEED_MAX_AUTHOR_BYTES | 2048 | bytes | Maximum normalized author size. |
FEED_MAX_CONTENT_BYTES | 2097152 | bytes | Maximum combined content and description size per entry (2 MiB). |
These are defensive limits, not routine performance targets. Raise one only when a trusted feed is known to exceed it and the added resource exposure is acceptable.
Proxy and Network Security
TRUST_PROXY
RSSMonster defaults to loopback, which is appropriate for a reverse proxy on the same host. It also accepts a positive proxy hop count or an Express trusted address/subnet expression. false disables proxy trust. The value true is rejected because trusting every proxy can let clients spoof their address and affect rate limiting.
Examples:
TRUST_PROXY=loopback
# TRUST_PROXY=1
# TRUST_PROXY=false
RSSMONSTER_INTERNAL_HOST_ALLOWLIST
Outbound feed requests block loopback, private, link-local, and other non-public address ranges to reduce server-side request-forgery risk. If you intentionally subscribe to an internal feed, add only its exact host, IP, CIDR, or host:port to the space-separated allowlist:
RSSMONSTER_INTERNAL_HOST_ALLOWLIST=feeds.internal.example 10.20.30.40:8080
Keep exceptions narrow. An allowlisted destination becomes reachable by the server’s feed-fetching code.
Rate Limiting
| Variable | Default | Description |
|---|---|---|
API_RATE_LIMIT_WINDOW_MS | 900000 | API rate-limit window in milliseconds (15 minutes). |
API_RATE_LIMIT_MAX | 600 | Requests allowed per client during the API window. |
MCP_RATE_LIMIT_WINDOW_MS | 900000 | MCP rate-limit window in milliseconds. |
MCP_RATE_LIMIT_MAX | 100 | Requests allowed per client during the MCP window. |
All values must be positive integers. Health checks and OPTIONS requests are excluded. Configure TRUST_PROXY correctly before tuning limits behind a reverse proxy so client addresses are interpreted correctly.
OpenAI and Agentic Features
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY | none | Enables agentic features and AI-backed enrichment that require OpenAI. |
OPENAI_MODEL_AGENT | gpt-5.1 | Model used by the natural-language assistant. |
OPENAI_MODEL_CRAWL | falls back to OPENAI_MODEL_NAME | Model used for crawl-time content analysis. The example sets it to gpt-4o-mini. |
INTERNAL_MCP_URL | http://127.0.0.1:$PORT/mcp | Server-controlled MCP endpoint used by the natural-language assistant. Configure this when MCP is reached through another container or an HTTPS listener. |
Without OPENAI_API_KEY, core RSS reading remains available, while features that require model calls are disabled. Model access creates external API usage and cost, so select models appropriate to your workload.
Recommendations
| Variable | Default | Description |
|---|---|---|
ARTICLE_RECOMMENDATION_MIN_SIMILARITY | 0.64 | Minimum cosine similarity for recent article recommendations. Valid range is -1 through 1. Higher values return fewer, closer matches. |
ARTICLE_RECOMMENDATION_MAX_CANDIDATES | 600 | Number of recent vectorized articles considered. Values are capped at 600. Lower values reduce query and scoring work. |
Zero recommendations is valid. Tune the similarity threshold cautiously and evaluate results across several users and feed mixes.
Client Build Configuration
| Variable | Example | Description |
|---|---|---|
VITE_APP_HOSTNAME | http://localhost:3000 | Base URL used by the browser for API requests. Use the public server origin. |
VITE_BASE_URL | / | Reserved in the example configuration; the current client does not read this custom variable. |
Vite embeds these values during npm run build. Restarting an already-built client without rebuilding does not apply changes. Development-only client behavior is derived automatically from Vite’s active mode.
Example Manual Configurations
Minimal SQLite server/.env:
NODE_ENV=production
DB_DIALECT=sqlite
DB_STORAGE=/var/lib/rssmonster/rssmonster.sqlite
JWT_SECRET=replace-with-a-long-random-secret
FEVER_CREDENTIAL_SECRET=replace-with-a-different-long-random-secret
TRUST_PROXY=loopback
MySQL with modest parallel crawling:
NODE_ENV=production
DB_DIALECT=mysql
DB_HOSTNAME=127.0.0.1
DB_PORT=3306
DB_DATABASE=rssmonster
DB_USERNAME=rssmonster
DB_PASSWORD=replace-with-a-strong-password
JWT_SECRET=replace-with-a-long-random-secret
FEVER_CREDENTIAL_SECRET=replace-with-a-different-long-random-secret
CRAWL_PARALLELPROCESSFLAG=1
FEED_PARALLEL_CONCURRENCY=3
CRAWL_WORKER_INTERVAL_MS=60000
TRUST_PROXY=loopback
Start with defaults, change one group of settings at a time, and inspect crawl statistics and logs before increasing concurrency or resource limits.