Skip to main content

Configuration

PullMD is configured with environment variables. With Docker Compose, put them in a .env file next to docker-compose.yml and run docker compose up -d to apply them. Every variable is optional unless marked.

Compose passthrough
PULLMD_ALLOWED_HOSTS, PULLMD_ALLOW_SIGNUP, PULLMD_ARTICLE_SERIES, PULLMD_COVERAGE_GUARD, PULLMD_EMBEDDED_IMAGES, PULLMD_EMBEDDED_IMAGES_MAX and PULLMD_FILENAME_DATE_PREFIX (marked † below) aren't passed through by the compose files as of v3.18.2. Add a line for each one you use to the pullmd service's environment: list, for example - PULLMD_ALLOWED_HOSTS=${PULLMD_ALLOWED_HOSTS:-}.

Server​

VariableDefaultDescription
PORT3000Host port the default compose file publishes. The container listens on 3000. Outside Docker, the port the server listens on.
PUBLIC_URLhttp://localhost:${PORT} (Traefik file: https://${HOST_DOMAIN})Public address of the instance. Used on /help, in the skill bundle and MCP share links, for OAuth, and to accept login forms. An https:// value marks the session cookie Secure. Unset (outside Docker), /help, the skill bundle and MCP share links use the protocol and host of each request.
HOST_DOMAINTraefik compose file only. Host name without scheme, used for routing.
PULLMD_TRUST_PROXYoff (Traefik file: 1)When to believe X-Forwarded-* headers: a hop count, true, or a list of proxy addresses. See Reverse proxy.
TZunsetTime zone, such as Europe/Berlin. Used for the PULLMD_FILENAME_DATE_PREFIX date, and for dates and times in uploaded e-mails (.eml, .msg), calendars (.ics) and feeds, which use Europe/Berlin when TZ is unset. The compose files don't set it; add - TZ=Europe/Berlin to the pullmd service's environment: list.
CACHE_DB/data/cache.dbPath of the SQLite database (cache, history, accounts). ./data/cache.db when run without Docker.

Sidecars​

VariableDefault (compose)Description
TRAFILATURA_URLhttp://trafilatura:8001/extractTrafilatura sidecar. Unset: Readability only.
PLAYWRIGHT_URLhttp://playwright:8002/renderHeadless browser sidecar. Unset: no rendering of JavaScript pages.
MARKITDOWN_URLhttp://markitdown:8003/convertDocument sidecar. Unset: document links, uploaded PDF, Office, EPUB and ZIP files, and uploaded images and audio without a provider return 502, and YouTube transcripts are off. The upload formats PullMD reads itself keep working. See Without MarkItDown.

Output​

VariableDefaultDescription
PULLMD_FRONTMATTER_FIELDSall fieldsComma-separated list of frontmatter fields to keep, such as title,url,source. Unknown names are ignored with a warning at startup. See Output format.
PULLMD_SOURCE_HEADERoffAny non-empty value, including false, adds the source line under the title that versions before 3.0 had. Leave it empty or unset to turn it off.
PULLMD_COVERAGE_GUARD †onoff disables the coverage guard.
PULLMD_ARTICLE_SERIES †onoff keeps one block when a page publishes one piece of writing as several short <article> blocks by the same author.
PULLMD_FILENAME_DATE_PREFIX †noneDate prefix for X-Suggested-Filename. Tokens YYYY MM DD HH mm ss, in the server's time zone (set TZ to change it). YYYY-MM-DD- gives 2026-08-01-YT-some-talk-dQw4w9WgXcQ.md. Characters outside A-Za-z0-9._- become -.

Cache and history​

VariableDefaultDescription
PULLMD_CACHE_RETENTION_DAYS90Days a conversion is kept after it was last written. A cache hit doesn't extend it; a new fetch of the URL does. 0 keeps everything. Range 0 to 36500. An invalid value logs a warning and uses 90.
DISABLE_PUBLIC_HISTORYfalsetrue, 1, yes or on (any case) hides everyone's history when sign-in is off: /api/history, /api/archive, DELETE /api/cache and DELETE /api/cache/:id return 403 to anonymous callers. Share links keep working.

Fetching​

VariableDefaultDescription
PULLMD_ALLOWED_HOSTS †noneInternal hosts or networks PullMD may fetch, such as 10.0.5.0/24,wiki.internal. See SSRF protection.
PULLMD_MAX_FETCH_BYTES52428800 (50 MB)Size limit for fetched pages and documents. Response headers must arrive within 15 seconds and the whole fetch must finish within 60 seconds. An invalid or non-positive value uses the default.
PULLMD_USER_AGENTrotatingFixed user agent for every web fetch.
PULLMD_UA_FEED_URLa public feed of current browser user agentsWhere the rotating user agents come from, refreshed every 48 hours. The default is a public feed on raw.githubusercontent.com, so PullMD makes an outbound request to it. PullMD keeps the desktop entries that start with Mozilla/ and uses the feed only when it has at least 5. Empty string: use the built-in list only.
PULLMD_SITE_RECIPESPath to your site recipes file, such as /data/site-recipes.json. Unset: PullMD loads data/site-recipes.json from its working directory when that file exists (outside Docker).

Authentication​

VariableDefaultDescription
PULLMD_AUTH_MODEdisableddisabled, single-admin or multi-user. See Authentication.
PULLMD_ADMIN_EMAILRequired on the first start with sign-in on. The first admin's email.
PULLMD_ADMIN_PASSWORDRequired on the first start with sign-in on. Any non-empty value is accepted; the admin commands and the sign-up form require at least 8 characters. Changing it later has no effect.
PULLMD_ALLOW_SIGNUP †onfalse, 0, no or off closes /signup in multi-user mode. Any other value keeps it open.
OAUTH_JWT_SECRETAt least 32 characters. Turns on OAuth for claude.ai and Claude Desktop. With a shorter value or without PUBLIC_URL, PullMD logs OAuth setup failed: and exits at startup.
PULLMD_AUTH_TOKENDeprecated shared bearer token, single-admin mode only.

Images, audio and OCR​

VariableDefaultDescription
PULLMD_VISION_API_KEYTurns on image captions.
PULLMD_VISION_BASE_URLOpenAIOpenAI-compatible API for captions.
PULLMD_VISION_MODELgpt-4o-miniCaption model.
PULLMD_STT_API_KEYTurns on audio transcripts.
PULLMD_STT_BASE_URLOpenAIOpenAI-compatible API for transcripts.
PULLMD_STT_MODELwhisper-1Transcription model.
PULLMD_LLM_API_KEYShared key for captions and transcripts when their own keys aren't set.
PULLMD_LLM_BASE_URLShared base URL for captions and transcripts.
PULLMD_PDF_OCR_API_KEYTurns on PDF optical character recognition (OCR). Doesn't fall back to the shared key.
PULLMD_PDF_OCR_BASE_URLhttps://api.mistral.ai/v1OCR API. The endpoint must speak the Mistral OCR API (POST /ocr).
PULLMD_PDF_OCR_MODELmistral-ocr-latestOCR model.
PULLMD_LLM_RATE_LIMIT30Requests per hour for captions, transcripts and OCR together, per user or address. 0 turns the limit off, and a non-numeric value uses 30. Over the limit, PullMD falls back to the regular conversion and doesn't cache that result. Uploaded images and audio go to the MarkItDown sidecar, and image and audio URLs go through web page extraction.
PULLMD_EMBEDDED_IMAGES †on-requestDescribe images in Reddit posts: off, on-request or always. An invalid value logs a warning and uses on-request. See Describe images in Reddit posts.
PULLMD_EMBEDDED_IMAGES_MAX †4Maximum images transcribed per post, 1 to 20.

There is no PULLMD_LLM_MODEL: the shared PULLMD_LLM_* settings cover the key and base URL only. If PULLMD_LLM_MODEL is set, PullMD logs a warning at startup and ignores it. Set PULLMD_VISION_MODEL, PULLMD_STT_MODEL or PULLMD_PDF_OCR_MODEL instead.

YouTube​

VariableDefaultDescription
MARKITDOWN_YOUTUBEoffAny non-empty value, including false, turns on YouTube transcripts. Set on the pullmd service.
MARKITDOWN_YT_TIMECODESlinkslinks, plain or none. Set on the markitdown service.
MARKITDOWN_YT_CHUNK30Transcript block length in seconds. 0 keeps each caption line.
MARKITDOWN_YT_LANGSfirst availablePreferred transcript languages, such as de,en.
MARKITDOWN_YT_PROXYHTTP(S) proxy for YouTube requests.

Reddit​

VariableDefaultDescription
REDDIT_CLIENT_IDReddit app credentials, needed to read Reddit. See Reddit credentials.
REDDIT_CLIENT_SECRETSecret for the Reddit app in REDDIT_CLIENT_ID.
REDDIT_USER_AGENTPullMD/1.0 (URL-to-Markdown service)Reddit requires a unique user agent: platform:appname:version (by u/yourname).
PULLMD_REDDIT_MORE_REQUESTS20 with credentials, 5 withoutExtra Reddit requests per conversion to load collapsed comments with comment_depth=all. Maximum 200, and 0 turns the loading off.

Document sidecar limits​

Set on the markitdown service.

VariableDefaultDescription
MARKITDOWN_CONVERT_TIMEOUT60Seconds before a conversion is stopped. 0 turns it off.
MARKITDOWN_MEM_LIMIT1gMemory limit for the container.
MARKITDOWN_MEM_LIMIT_MB0Memory cap per conversion in MB. 0 uses the container limit.

Fixed limits​

PullMD enforces these limits, and none has a setting:

LimitValue
POST /api/html body10 MB
POST /api/file body25 MB
/mcp request body1 MB
Login attempts10 per minute per address
Signups5 per hour per address
Unknown share-link lookups120 per minute per address
OAuth authorization (/oauth/authorize, /oauth/consent)60 per minute per address
OAuth token requests (/oauth/token, /oauth/revoke)60 per minute per address
OAuth client registrations (/oauth/register)10 per hour per address
Cache freshness1 hour