charts

firecrawl

Version: 2.0.15 Type: application AppVersion: 2.11.159 Artifact Hub

Firecrawl is an open-source API that crawls websites and turns them into LLM-ready data (markdown, HTML, structured JSON). This chart packages the self-hosted topology — API, workers, Playwright renderer and the bundled Redis / RabbitMQ / NuQ-Postgres backends — using the bjw-s common library, with official ghcr.io images.

TL;DR

helm repo add obeone https://charts.obeone.cloud
helm repo update
helm install firecrawl obeone/firecrawl

About

Firecrawl is a web scraping and crawling API that turns websites into LLM-ready data: clean markdown, structured extraction, screenshots, search. This chart deploys the complete self-hosted stack: the API and its workers, the Playwright service used for browser rendering, plus the Redis, RabbitMQ and nuq-postgres backing services.

Prerequisites

Configuration

This chart is built on the bjw-s-labs common library. Most configuration keys (controllers, service, ingress, persistence, …) follow its schema; see the common library documentation for everything it supports beyond what is spelled out in values.yaml.

Defaults are meant to work out of the box on any cluster. The full list of options lives in values.yaml, is validated by values.schema.json at install time, and is documented in the Values section below. Override it with your own values file:

helm install firecrawl obeone/firecrawl -f my-values.yaml

Upgrading

helm repo update
helm upgrade firecrawl obeone/firecrawl

Each release lists its changes in the Artifact Hub changelog; give it a look before jumping across several chart versions.

Uninstalling

helm uninstall firecrawl

PersistentVolumeClaims created by the chart are kept around: delete them manually if you also want the data gone.

Requirements

Kubernetes: >=1.25.0-0

Repository Name Version
https://bjw-s-labs.github.io/helm-charts common 4.6.2

Values

Key Type Default Description  
configMaps object {"config":{"data":{"ENV":"production","EXTRACT_WORKER_PORT":"3004","FIRECRAWL_APP_SCHEME":"http","HOST":"0.0.0.0","IS_KUBERNETES":"true","LOGGING_LEVEL":"INFO","MODEL_EMBEDDING_NAME":"","MODEL_NAME":"","NUM_WORKERS_PER_QUEUE":"8","NUQ_PREFETCH_WORKER_PORT":"3011","NUQ_WORKER_COUNT":"1","NUQ_WORKER_PORT":"3006","OLLAMA_BASE_URL":"","OPENAI_BASE_URL":"","PORT":"3002","PROXY_SERVER":"","PROXY_USERNAME":"","SEARXNG_CATEGORIES":"","SEARXNG_ENDPOINT":"","SEARXNG_ENGINES":"","SELF_HOSTED_WEBHOOK_URL":"","USE_DB_AUTHENTICATION":"false","WORKER_PORT":"3005"},"enabled":true},"playwright-config":{"data":{"ALLOW_LOCAL_WEBHOOKS":"","BLOCK_MEDIA":"true","MAX_CONCURRENT_PAGES":"10","PORT":"3000","PROXY_SERVER":"","PROXY_USERNAME":""},"enabled":true}} ————————————————————————— Shared by the API and worker containers. Connection URLs are NOT here — they need template rendering and live in env (see the anchors at the top).  
configMaps.config.data.ENV string "production" Runtime environment (production development).
configMaps.config.data.FIRECRAWL_APP_SCHEME string "http" URL scheme the app advertises for its own public URLs (http https). Set to https when serving the API over TLS.
configMaps.config.data.LOGGING_LEVEL string "INFO" Log verbosity (e.g. INFO, DEBUG, WARN, ERROR).  
configMaps.config.data.MODEL_EMBEDDING_NAME string "" Embedding model name.  
configMaps.config.data.MODEL_NAME string "" LLM model name used for JSON mode / extract.  
configMaps.config.data.NUM_WORKERS_PER_QUEUE string "8" Concurrent jobs each worker pulls per queue. Raise for per-pod throughput, or add replicas to scale across pods.  
configMaps.config.data.NUQ_WORKER_COUNT string "1" NuQ worker loops per pod (intra-pod concurrency). Total concurrency = controllers.nuq-worker.replicas x this value.  
configMaps.config.data.OLLAMA_BASE_URL string "" Local Ollama base URL — must include /api, e.g. http://ollama:11434/api. For Ollama set this + MODEL_NAME + MODEL_EMBEDDING_NAME and leave OPENAI_* empty.  
configMaps.config.data.OPENAI_BASE_URL string "" OpenAI-compatible base URL (leave empty for OpenAI itself; set OPENAI_API_KEY in the secret).  
configMaps.config.data.PROXY_SERVER string "" Proxy server URL or IP:PORT.  
configMaps.config.data.PROXY_USERNAME string "" Proxy username (leave blank if unauthenticated).  
configMaps.config.data.SEARXNG_CATEGORIES string "" Optional comma-separated categories.  
configMaps.config.data.SEARXNG_ENDPOINT string "" URL of an external SearXNG metasearch instance (required for /search).  
configMaps.config.data.SEARXNG_ENGINES string "" Optional comma-separated engines, e.g. google,bing.  
configMaps.config.data.SELF_HOSTED_WEBHOOK_URL string "" Receives crawl/scrape completion callbacks; signed by SELF_HOSTED_WEBHOOK_HMAC_SECRET (in the secret) when set.  
configMaps.config.data.USE_DB_AUTHENTICATION string "false" DB-backed auth needs Supabase, which self-hosted cannot configure; leave false (this deliberately differs from upstream .env.example, which ships true). With false the API performs NO request authentication — protect it at the network/ingress layer.  
configMaps.playwright-config.data.ALLOW_LOCAL_WEBHOOKS string "" Let the renderer POST to RFC1918/localhost targets. Off by default for SSRF safety; use with care.  
configMaps.playwright-config.data.BLOCK_MEDIA string "true" Block images/video/fonts in the headless browser (faster scrapes).  
configMaps.playwright-config.data.MAX_CONCURRENT_PAGES string "10" Max concurrent browser pages.  
configMaps.playwright-config.data.PROXY_SERVER string "" Headless-browser proxy server URL or IP:PORT.  
configMaps.playwright-config.data.PROXY_USERNAME string "" Headless-browser proxy username (leave blank if unauthenticated).  
controllers object {"api":{"containers":{"api":{"args":["--max-old-space-size=2048","dist/src/index.js"],"command":["node"],"env":{"<<":[{"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""},{"NUQ_POD_NAME":{"valueFrom":{"fieldRef":{"fieldPath":"metadata.name"}}}}],"FLY_PROCESS_GROUP":"app"},"envFrom":[{"configMap":"config"},{"secret":"secrets"}],"image":{"pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/firecrawl","tag":""},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/v0/health/liveness","port":3002},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/v0/health/readiness","port":3002},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}}},"resources":{"limits":{"cpu":"2","memory":"2560Mi"},"requests":{"cpu":"250m","memory":"512Mi"}}}},"enabled":true,"strategy":"RollingUpdate"},"extract-worker":{"containers":{"extract-worker":{"args":["--max-old-space-size=1536","dist/src/services/extract-worker.js"],"command":["node"],"env":{"<<":[{"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""},{"NUQ_POD_NAME":{"valueFrom":{"fieldRef":{"fieldPath":"metadata.name"}}}}],"FLY_PROCESS_GROUP":"extract-worker"},"envFrom":[{"configMap":"config"},{"secret":"secrets"}],"image":{"pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/firecrawl","tag":""},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/liveness","port":3004},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3004},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":5}}},"resources":{"limits":{"cpu":"1","memory":"2Gi"},"requests":{"cpu":"250m","memory":"512Mi"}}}},"enabled":true,"strategy":"RollingUpdate"},"nuq-postgres":{"containers":{"postgres":{"env":{"PGDATA":"/var/lib/postgresql/data/pgdata","POSTGRES_DB":"","POSTGRES_PASSWORD":"","POSTGRES_USER":""},"image":{"digest":"sha256:f9388bd25ae2e1f1d034518236f993ce236173c1d8800ce24092ea6643a95a33","pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/nuq-postgres","tag":"latest"},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":6,"initialDelaySeconds":20,"periodSeconds":10,"tcpSocket":{"port":5432},"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":6,"initialDelaySeconds":10,"periodSeconds":5,"tcpSocket":{"port":5432},"timeoutSeconds":3}}},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"100m","memory":"256Mi"}}}},"enabled":true,"strategy":"Recreate"},"nuq-prefetch-worker":{"containers":{"nuq-prefetch-worker":{"args":["--max-old-space-size=1024","dist/src/services/worker/nuq-prefetch-worker.js"],"command":["node"],"env":{"<<":[{"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""},{"NUQ_POD_NAME":{"valueFrom":{"fieldRef":{"fieldPath":"metadata.name"}}}}],"FLY_PROCESS_GROUP":"nuq-prefetch-worker","NUQ_PREFETCH_REPLICAS":"1"},"envFrom":[{"configMap":"config"},{"secret":"secrets"}],"image":{"pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/firecrawl","tag":""},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3011},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3011},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":5}}},"resources":{"limits":{"cpu":"500m","memory":"1536Mi"},"requests":{"cpu":"100m","memory":"256Mi"}}}},"enabled":true,"strategy":"RollingUpdate"},"nuq-worker":{"containers":{"nuq-worker":{"args":["--max-old-space-size=1536","dist/src/services/worker/nuq-worker.js"],"command":["node"],"env":{"<<":[{"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""},{"NUQ_POD_NAME":{"valueFrom":{"fieldRef":{"fieldPath":"metadata.name"}}}}],"FLY_PROCESS_GROUP":"nuq-worker"},"envFrom":[{"configMap":"config"},{"secret":"secrets"}],"image":{"pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/firecrawl","tag":""},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3006},"initialDelaySeconds":5,"periodSeconds":5,"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3006},"initialDelaySeconds":5,"periodSeconds":5,"timeoutSeconds":5}}},"resources":{"limits":{"cpu":"1","memory":"2Gi"},"requests":{"cpu":"250m","memory":"512Mi"}}}},"enabled":true,"replicas":1,"strategy":"RollingUpdate"},"playwright":{"containers":{"playwright":{"envFrom":[{"configMap":"playwright-config"},{"secret":"secrets"}],"image":{"digest":"sha256:1f6eba6403207d501a63d9b1d4685b6316b4fc7968fe64a5839ab1bfec9d1c14","pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/playwright-service","tag":"latest"},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3000},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/health","port":3000},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}}},"resources":{"limits":{"cpu":"2","memory":"2Gi"},"requests":{"cpu":"250m","memory":"512Mi"}}}},"enabled":true,"strategy":"RollingUpdate"},"rabbitmq":{"containers":{"rabbitmq":{"env":{"RABBITMQ_DEFAULT_PASS":"","RABBITMQ_DEFAULT_USER":""},"image":{"pullPolicy":"IfNotPresent","repository":"docker.io/library/rabbitmq","tag":"3.13-management-alpine"},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":6,"initialDelaySeconds":20,"periodSeconds":10,"tcpSocket":{"port":5672},"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":6,"initialDelaySeconds":10,"periodSeconds":5,"tcpSocket":{"port":5672},"timeoutSeconds":3}}},"resources":{"limits":{"cpu":"500m","memory":"512Mi"},"requests":{"cpu":"100m","memory":"256Mi"}}}},"enabled":true},"redis":{"containers":{"redis":{"args":["--bind","0.0.0.0"],"command":["redis-server"],"image":{"pullPolicy":"IfNotPresent","repository":"docker.io/library/redis","tag":"7.4-alpine"},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"initialDelaySeconds":15,"periodSeconds":20,"tcpSocket":{"port":6379},"timeoutSeconds":5}},"readiness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"tcpSocket":{"port":6379},"timeoutSeconds":3}}},"resources":{"limits":{"cpu":"250m","memory":"256Mi"},"requests":{"cpu":"50m","memory":"64Mi"}}}},"enabled":true},"worker":{"containers":{"worker":{"args":["--max-old-space-size=1536","dist/src/services/queue-worker.js"],"command":["node"],"env":{"<<":[{"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""},{"NUQ_POD_NAME":{"valueFrom":{"fieldRef":{"fieldPath":"metadata.name"}}}}],"FLY_PROCESS_GROUP":"worker"},"envFrom":[{"configMap":"config"},{"secret":"secrets"}],"image":{"pullPolicy":"IfNotPresent","repository":"ghcr.io/firecrawl/firecrawl","tag":""},"probes":{"liveness":{"custom":true,"enabled":true,"spec":{"failureThreshold":3,"httpGet":{"path":"/liveness","port":3005},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":5}},"readiness":{"enabled":false}},"resources":{"limits":{"cpu":"1","memory":"2Gi"},"requests":{"cpu":"250m","memory":"512Mi"}}}},"enabled":true,"strategy":"RollingUpdate"}} ————————————————————————— Each controller’s probe port/path is specific to its own HTTP health server and is NOT interchangeable. Every numeric probe port must match the matching *_PORT in configMaps.config below — change one without the other and the pod crash-loops on failing health checks.  
controllers.api.containers.api.args list ["--max-old-space-size=2048","dist/src/index.js"] V8 old-space heap ceiling (MiB). Keep it safely below the memory limit (2048 heap vs 2560Mi limit); the gap absorbs non-heap usage. For heavy crawls raise this AND limits.memory together — raising only one risks OOMKill or premature GC.  
controllers.extract-worker.containers.extract-worker.args list ["--max-old-space-size=1536","dist/src/services/extract-worker.js"] V8 old-space heap ceiling (MiB); keep below this container’s limit.  
controllers.nuq-postgres.containers.postgres.env.PGDATA string "/var/lib/postgresql/data/pgdata" Postgres data dir. MUST be a subdirectory of the mounted volume, not the mount root: a real PVC (any ext4/xfs CSI volume, e.g. Longhorn) ships a lost+found, and initdb refuses a non-empty data dir → CrashLoopBackOff. Pointing PGDATA at a subdir sidesteps it.  
controllers.nuq-postgres.containers.postgres.image.tag string "latest" Upstream only publishes a floating latest; pinned by digest. The digest takes precedence over the tag, so bump BOTH together. Current digests: ghcr.io/firecrawl/nuq-postgres.  
controllers.nuq-prefetch-worker.containers.nuq-prefetch-worker.args list ["--max-old-space-size=1024","dist/src/services/worker/nuq-prefetch-worker.js"] V8 old-space heap ceiling (MiB); keep below this container’s limit.  
controllers.nuq-prefetch-worker.containers.nuq-prefetch-worker.env.NUQ_PREFETCH_REPLICAS string "1" Total number of prefetch-worker pods; MUST equal this controller’s replicas (unset above, so it defaults to 1). Prefetch workers shard the queue by replica index, so a mismatch drops or double-processes jobs. To scale, raise BOTH together.  
controllers.nuq-worker.containers.nuq-worker.args list ["--max-old-space-size=1536","dist/src/services/worker/nuq-worker.js"] V8 old-space heap ceiling (MiB); keep below this container’s limit.  
controllers.nuq-worker.replicas int 1 Number of nuq-worker pods. Total NuQ concurrency = replicas x configMaps.config.NUQ_WORKER_COUNT (per-pod loops): scale pods for throughput, raise NUQ_WORKER_COUNT for per-pod concurrency. Keep NUQ_WORKER_COUNT sensible relative to the pods you run.  
controllers.playwright.containers.playwright.image.tag string "latest" Upstream only publishes a floating latest; pinned by digest for reproducibility. The digest takes precedence over the tag, so bump BOTH together (changing only the tag has no effect). Current digests: ghcr.io/firecrawl/playwright-service.  
controllers.redis.containers.redis.args list ["--bind","0.0.0.0"] Binds 0.0.0.0 with no password; reachable by any in-cluster client (ClusterIP only). Rely on NetworkPolicy / namespace isolation, or use an external authenticated Redis via firecrawl.redis.url.  
controllers.worker.containers.worker.args list ["--max-old-space-size=1536","dist/src/services/queue-worker.js"] V8 old-space heap ceiling (MiB); keep below this container’s limit.  
defaultPodOptions object {"automountServiceAccountToken":false} —————————————————————————  
firecrawl object {"database":{"url":""},"playwright":{"url":""},"rabbitmq":{"url":""},"redis":{"url":""}} —————————————————————————  
firecrawl.database.url string "" External NuQ Postgres URL (postgresql://user:pass@host:5432/db). MUST be the upstream nuq-postgres image (custom schema). Same two-step swap. Empty = use the bundled DB.  
firecrawl.playwright.url string "" External Playwright URL. MUST include the /scrape path, e.g. http://playwright.example.com:3000/scrape. Same two-step swap. Empty = use the bundled Playwright.  
firecrawl.rabbitmq.url string "" External RabbitMQ AMQP URL (amqp://user:pass@host:5672). Same two-step swap. Empty = use the bundled broker.  
firecrawl.redis.url string "" External Redis URL (e.g. redis://user:pass@host:6379). To use it, set this AND controllers.redis.enabled: false + service.redis.enabled: false. Disabling the bundled Redis without setting this breaks every worker (the fallback URL points at the now-missing Service). Empty = use the bundled Redis.  
ingress object {"api":{"enabled":false,"hosts":[{"host":"firecrawl.example.com","paths":[{"path":"/","pathType":"Prefix","service":{"identifier":"api","port":"http"}}]}]}} —————————————————————————  
ingress.api.enabled bool false Expose the API via Ingress. The API is unauthenticated — protect it before exposing (see USE_DB_AUTHENTICATION and BULL_AUTH_KEY). When serving over TLS, also set configMaps.config FIRECRAWL_APP_SCHEME=https.  
ingress.api.hosts list [{"host":"firecrawl.example.com","paths":[{"path":"/","pathType":"Prefix","service":{"identifier":"api","port":"http"}}]}] Ingress hostnames for the API.  
nuqPostgres object {"auth":{"database":"postgres","password":"postgres","username":"postgres"}} ————————————————————————— These feed BOTH the Postgres container env (POSTGRES_USER/PASSWORD/DB) AND the NUQ_DATABASE_URL connection string — keep them consistent. Avoid URL-special characters (@ : / %) in the password: it is embedded unescaped into the postgresql:// URL. The DB is never exposed outside the cluster; for production prefer an external managed Postgres via firecrawl.database.url.  
nuqPostgres.auth.database string "postgres" Database name (also feeds NUQ_DATABASE_URL).  
nuqPostgres.auth.password string "postgres" Set a strong password before deploying (plaintext in the manifest, as above).  
nuqPostgres.auth.username string "postgres" Postgres superuser name (also feeds NUQ_DATABASE_URL).  
persistence object {"nuq-postgres-data":{"accessMode":"ReadWriteOnce","advancedMounts":{"nuq-postgres":{"postgres":[{"path":"/var/lib/postgresql/data"}]}},"enabled":true,"size":"10Gi","type":"persistentVolumeClaim"}} ————————————————————————— Only the NuQ Postgres data volume is stateful. Losing the bundled Redis / RabbitMQ pods drops in-flight queue state and rate-limit counters (acceptable for transient jobs — resubmit if needed). The size below sizes the NuQ queue DB, not scraped output (which is returned to the client, never stored).  
persistence.nuq-postgres-data.advancedMounts object {"nuq-postgres":{"postgres":[{"path":"/var/lib/postgresql/data"}]}} StorageClass for the PVC (omit / empty = cluster default). storageClass: “” advancedMounts targets a controller/container by name: the nuq-postgres key MUST match controllers.nuq-postgres and postgres MUST match its container. Rename either and the volume silently mounts nowhere — Postgres writes to ephemeral storage and loses all data on restart, no error.  
persistence.nuq-postgres-data.size string "10Gi" PVC size for the NuQ Postgres data volume.  
rabbitmq object {"auth":{"password":"firecrawl","username":"firecrawl"}} ————————————————————————— Interpolated into NUQ_RABBITMQ_URL, so these end up visible in plaintext in the rendered manifest (helm get manifest / kubectl get pod -o yaml). For real secrecy, use an external broker via firecrawl.rabbitmq.url.  
rabbitmq.auth.password string "firecrawl" Set a strong password before deploying to anything reachable.  
rabbitmq.auth.username string "firecrawl" RabbitMQ username; must NOT be guest (RabbitMQ rejects guest over non-loopback connections), hence a named user.  
route object {"api":{"enabled":false,"hostnames":["firecrawl.example.com"],"kind":"HTTPRoute","parentRefs":[{"name":"gateway","namespace":"gateway-system","sectionName":"http"}],"rules":[{"backendRefs":[{"identifier":"api","port":"http"}],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}} —————————————————————————  
route.api.enabled bool false Expose the API via an HTTPRoute (Gateway API). See the ingress security note above before enabling.  
secrets object {"secrets":{"enabled":true,"stringData":{"BULL_AUTH_KEY":"CHANGEME","LLAMAPARSE_API_KEY":"","OPENAI_API_KEY":"","PROXY_PASSWORD":"","SELF_HOSTED_WEBHOOK_HMAC_SECRET":"","SLACK_WEBHOOK_URL":"","TEST_API_KEY":""}}} ————————————————————————— To manage these outside the chart, set enabled: false and create a Secret named <release-fullname>-secrets (the secret: secrets reference is fullname-prefixed by the common library) with the same keys. That Secret is also mounted into the Playwright container (for PROXY_PASSWORD), not only the Firecrawl workers.  
secrets.secrets.stringData.BULL_AUTH_KEY string "CHANGEME" Protects the admin queue dashboard at /admin//queues (the URL embeds this key verbatim; the dashboard shows the legacy BullMQ queues). The API itself is unauthenticated — this only guards /admin. CHANGE THIS on any deployment reachable from untrusted networks.  
secrets.secrets.stringData.LLAMAPARSE_API_KEY string "" LlamaParse key for PDF parsing.  
secrets.secrets.stringData.OPENAI_API_KEY string "" OpenAI (or compatible) API key to enable AI features.  
secrets.secrets.stringData.PROXY_PASSWORD string "" Password for the outbound proxy (used by both the HTTP-fetch and Playwright proxies, if PROXY_SERVER is set).  
secrets.secrets.stringData.SELF_HOSTED_WEBHOOK_HMAC_SECRET string "" HMAC secret signing self-hosted webhook payloads (optional).  
secrets.secrets.stringData.SLACK_WEBHOOK_URL string "" Slack webhook for server health notifications.  
secrets.secrets.stringData.TEST_API_KEY string "" API key used by Firecrawl’s own integration/e2e tests against this instance. Not needed for normal operation; leave empty.  
service object {"api":{"controller":"api","enabled":true,"ports":{"http":{"port":3002}}},"nuq-postgres":{"controller":"nuq-postgres","enabled":true,"ports":{"postgres":{"port":5432}}},"playwright":{"controller":"playwright","enabled":true,"ports":{"http":{"port":3000}}},"rabbitmq":{"controller":"rabbitmq","enabled":true,"ports":{"amqp":{"port":5672},"management":{"port":15672}}},"redis":{"controller":"redis","enabled":true,"ports":{"redis":{"port":6379}}}} ————————————————————————— Only api (and optionally playwright) is meant to be consumed; redis, rabbitmq and nuq-postgres are internal cluster wiring. Workers expose health ports probed directly by the kubelet, so they need no Service of their own. The RabbitMQ management UI on 15672 is for debugging via port-forward.  
x-firecrawl-connection-env object {"NUQ_DATABASE_URL":"","NUQ_DATABASE_URL_LISTEN":"","NUQ_RABBITMQ_URL":"","PLAYWRIGHT_MICROSERVICE_URL":"","REDIS_RATE_LIMIT_URL":"","REDIS_URL":""} ————————————————————————— The three x-firecrawl-* keys below are anchor SOURCES, not configurable values: Helm ignores top-level x-* keys, so they never render on their own. They are merged into every Firecrawl app container’s env via env: { <<: [*firecrawl-connection-env, *firecrawl-pod-env], ... }. Editing an anchor here changes ALL FIVE Firecrawl containers at once (api, worker, extract-worker, nuq-worker, nuq-prefetch-worker). The Playwright service is configured separately and does NOT receive these. To repoint a backend, set firecrawl.<backend>.url below — do not edit these templates. The values are rendered through the common library’s tpl pass, so the printf fallbacks resolve to the in-cluster Service DNS names (-redis, -playwright, -nuq-postgres, -rabbitmq) and ports. Those must stay in lockstep with the `controllers.*` / `service.*` names and the port values in `configMaps.config`; rename a service or change a port and you must update the matching printf here too (or use a `firecrawl.*.url` override).  
x-firecrawl-env-from[0].configMap string "config"    
x-firecrawl-env-from[1].secret string "secrets"    
x-firecrawl-pod-env.NUQ_POD_NAME.valueFrom.fieldRef.fieldPath string "metadata.name"    

Verifying the chart signature

Charts in this repository are signed with GPG and every release ships a provenance file. The public key is available at charts.obeone.cloud/public_key.gpg, fingerprint B9FE852F28888D27F8C9A11CD33E04CD22E335CE.

# Import the signing key into a legacy keyring (helm verifies with GnuPG v1 keyrings)
curl -fsSL https://charts.obeone.cloud/public_key.gpg | gpg --import
gpg --export > ~/.gnupg/pubring.gpg

# Pull the chart and check it against its provenance file
helm pull --verify obeone/firecrawl

Support

This is a personal chart repository, maintained on a best-effort basis. Bug reports and contributions are welcome on GitHub.


Autogenerated from chart metadata using helm-docs v1.14.2