Configuration
Palena is configured by a single YAML file with environment variable overrides. The fully annotated example ships at config/palena.example.yaml — copy it to palena.yaml and edit from there.
Loading order
- Built-in defaults (compiled into the binary).
- YAML file at the path in
PALENA_CONFIG_PATH(default:./palena.yaml, inside the container:/config/palena.yaml). - Environment variables override any YAML value they are defined for.
Start the server with an explicit path:
PALENA_CONFIG_PATH=/etc/palena/palena.yaml /palenaEnvironment variable naming
The pattern is PALENA_<SECTION>_<KEY>, uppercase, with underscores:
| YAML key | Env variable |
|---|---|
server.port | PALENA_SERVER_PORT |
search.searxngURL | PALENA_SEARCH_SEARXNG_URL |
scraper.playwright.endpoint | PALENA_SCRAPER_PLAYWRIGHT_ENDPOINT |
pii.mode | PALENA_PII_MODE |
reranker.provider | PALENA_RERANKER_PROVIDER |
policy.domains.mode | PALENA_POLICY_DOMAINS_MODE |
Env variables always win. Useful in Compose / Kubernetes where secret values (API keys for hosted rerankers, proxy credentials) should never live in YAML.
Sections
server
HTTP listener settings.
server:
host: "0.0.0.0"
port: 8080
readTimeout: 30s
writeTimeout: 60ssearch
SearXNG integration and engine routing.
search:
searxngURL: "http://searxng:8080" # required
defaultEngines: ["google", "duckduckgo", "brave"]
engineRoutes:
general: ["google", "duckduckgo", "brave"]
news: ["google news", "duckduckgo", "bing news"]
code: ["github", "stackoverflow", "duckduckgo"]
science: ["google scholar", "duckduckgo", "wikipedia"]
defaultLanguage: "en"
safeSearch: 1 # 0=off, 1=moderate, 2=strict
maxResults: 10 # before reranking
timeout: 10s
queryExpansion:
enabled: false
maxVariants: 2maxResults here is the pre-rerank pool. The tool's maxResults argument (1–20) then picks the top K from this pool. Keeping this larger than the tool's maxResults gives the reranker something to re-rank.
scraper
Tiered extraction. Details in Scraping.
scraper:
maxConcurrency: 5 # parallel workers across all URLs
timeouts:
httpGet: 10s # L0
browserPage: 15s # L1/L2 per-page
browserNav: 30s # L1/L2 navigation
playwright:
endpoint: "ws://playwright:3000" # empty string disables L1/L2
maxTabs: 3
stealth:
enabled: true
randomizeViewport: true
randomizeUserAgent: true
proxy:
enabled: false
pool: []
cooldownSeconds: 300
contentDetection:
minTextLength: 500
minTextRatio: 0.05
maxScriptTags: 5Setting scraper.playwright.endpoint: "" disables L1 and L2 entirely — useful for a lightweight footprint where only L0-eligible pages need to work.
policy
Pre-scrape filtering. Details in PII & Compliance — policy gates.
policy:
robots:
enabled: true
cacheSeconds: 3600
domains:
mode: "blocklist" # "allowlist" or "blocklist"
allowlist: [] # suffix match — "github.com" covers "docs.github.com"
blocklist: []
rateLimit:
enabled: true
requestsPerDomainPerMinute: 10pii
Presidio integration. Details in PII & Compliance.
pii:
enabled: true
mode: "audit" # audit | redact | block
analyzerURL: "http://presidio-analyzer:5002"
anonymizerURL: "http://presidio-anonymizer:5001"
language: "en"
scoreThreshold: 0.5
blockThreshold: 5.0 # entities per 1000 chars (mode=block)
entities:
- PERSON
- EMAIL_ADDRESS
- PHONE_NUMBER
- CREDIT_CARD
- IBAN_CODE
- IP_ADDRESS
- LOCATION
- US_SSN
- MEDICAL_LICENSE
anonymizers:
DEFAULT: { type: replace, newValue: "<REDACTED>" }
PERSON: { type: replace, newValue: "<PERSON>" }
EMAIL_ADDRESS: { type: mask, maskingChar: "*", charsToMask: 100, fromEnd: false }
PHONE_NUMBER: { type: replace, newValue: "<PHONE>" }
timeout: 5sreranker
Pluggable reranker. Details in Reranking.
reranker:
provider: "flashrank" # kserve | flashrank | rankllm | none
endpoint: "http://flashrank:8080"
model: "" # provider-specific
topK: 5
timeout: 10sprovenance
Hash chain and audit export. Details in Provenance.
provenance:
enabled: true
clickhouse:
enabled: false
endpoint: "http://clickhouse:8123"
database: "palena"
table: "palena_provenance"
batchSize: 50
flushInterval: 5sotel
Traces and metrics. Details in Observability.
otel:
enabled: true
serviceName: "palena"
traceExporter: "otlp" # otlp | stdout | none
traceEndpoint: "otel-collector:4317"
metricExporter: "prometheus" # prometheus | otlp | stdout | none
metricEndpoint: "otel-collector:4317"
sampleRate: 1.0
exportTimeout: 10sWith metricExporter: prometheus, metrics are served at GET /metrics on the main Palena port.
logging
logging:
level: "info" # debug | info | warn | error
format: "json" # json | textShip these to any collector (Loki, ELK, Datadog, etc.). PII audit records are emitted as structured log events at INFO with the fixed message "pii: audit".
Recipes
Tighten PII enforcement for a healthtech deployment
pii:
mode: "redact" # no raw PII reaches the LLM
scoreThreshold: 0.4 # catch lower-confidence detections
entities:
- PERSON
- EMAIL_ADDRESS
- PHONE_NUMBER
- US_SSN
- MEDICAL_LICENSE
- DATE_TIME # add if DoBs matter
- LOCATION # add if addresses matterBlock content-heavy PII pages entirely
pii:
mode: "block"
blockThreshold: 3.0 # > 3 entities / 1000 chars → dropUse a GPU reranker in production
reranker:
provider: "kserve"
endpoint: "http://mxbai-rerank.kserve.svc.cluster.local:8080"
model: "mixedbread-ai/mxbai-rerank-large-v2"
topK: 5Restrict to an enterprise allowlist
policy:
domains:
mode: "allowlist"
allowlist:
- "wikipedia.org"
- "arxiv.org"
- "nih.gov"
- "ec.europa.eu"
rateLimit:
enabled: true
requestsPerDomainPerMinute: 30L0-only (no browser)
scraper:
playwright:
endpoint: "" # disables L1/L2Saves about 1.5 GB of RAM and the Playwright sidecar.
Route through a proxy pool for L2
scraper:
proxy:
enabled: true
pool:
- url: "http://user:pass@proxy-us.example.com:8080"
region: "us"
- url: "socks5://user:pass@proxy-eu.example.com:1080"
region: "eu"
cooldownSeconds: 600Wire up the full provenance trail
provenance:
enabled: true
clickhouse:
enabled: true
endpoint: "http://clickhouse.observability.svc.cluster.local:8123"
database: "palena"
table: "palena_provenance"
batchSize: 100
flushInterval: 10sValidation
Palena validates configuration at startup and refuses to start on:
- Missing
search.searxngURL. pii.modeoutsideaudit/redact/block.reranker.provideroutsidekserve/flashrank/rankllm/none.reranker.provider != nonebutreranker.endpointempty.policy.domains.modeoutsideallowlist/blocklist.- Negative or zero timeouts.
Validation errors are logged at startup with the specific key that failed. Fix the config and restart.
Related
- Getting Started — running the defaults.
- Scraping — tuning content detection and browser behavior.
- Observability — OTel exporter setup in detail.