
Deploy Firecrawl · Quick Start
Self-hosted web scraping and crawling API for LLMs, behind an API key
playwright-service
Just deployed
redis
Just deployed
/data
nuq-postgres
Just deployed
/var/lib/postgresql/data
Just deployed
rabbitmq
Just deployed
/var/lib/rabbitmq
gateway
Just deployed
Just deployed
Deploy and Host Firecrawl on Railway
Firecrawl is an open-source API that turns websites into clean markdown and structured data for LLM applications. It scrapes single pages, crawls whole sites, maps a site's URLs and searches the web. With an LLM provider connected, it also extracts structured JSON. This template runs the official self-hosted stack from the Firecrawl repository and puts an API key in front of it, so your instance is not open to the internet.
About Hosting Firecrawl
- The upstream self-hosted stack. It runs the same services as Firecrawl's
docker-compose.yaml:api,worker,playwright-service(headless Chromium),nuq-postgres(the Postgres job queue),redisandrabbitmq. A small Caddygatewaysits in front of them. - Official images on moving tags.
ghcr.io/firecrawl/firecrawl:latest,ghcr.io/firecrawl/playwright-service:latest,ghcr.io/firecrawl/nuq-postgres:latest,redis:alpine,rabbitmq:3-managementandcaddy:latest. A redeploy picks up new releases. - An API key is required. Self-hosted Firecrawl has no authentication of its own unless you run Supabase (
USE_DB_AUTHENTICATION=falseupstream). The gateway is the only public service. It answers any request withoutAuthorization: Bearer {FIRECRAWL_API_KEY}with401. The key is generated when you deploy. - The queue admin UI is locked. Bull Board is reachable only at
/admin/{BULL_AUTH_KEY}/queues, and the 32-character key is generated at deploy time. Every other/adminpath returns404, even when the request carries the API key. - No default passwords. The Postgres, Redis and RabbitMQ passwords are generated. None of the data services has a public domain or a TCP proxy. All services talk over Railway's private network.
- Durable. Volumes hold Postgres (queue and crawl state), Redis and RabbitMQ data. Crawl results, keys and the admin UI survive a redeploy of every service.
- A complete worker. The
workerservice runs the same processes as upstream's all-in-one runner: the queue worker, the extract worker, five NuQ workers, the prefetch worker and the reconciler. If any one of them exits, the service restarts. - Healthchecks. The gateway is checked at
/healthz, the API at/v0/health/liveness, the worker at/healthand Playwright at/health. - LLM keys are optional. Scrape, crawl, map, batch scrape and search work without any key. Extract, the JSON format and summaries need an OpenAI-compatible key or an Ollama server.
Getting started
- Click Deploy. Leave the LLM fields empty if you only need scraping and crawling. The first boot takes a few minutes while the images are pulled.
- Open the gateway service, then Variables. Copy
FIRECRAWL_API_URL(your public URL) andFIRECRAWL_API_KEY(your key). - Check that the stack is up. This request needs no key:
curl https://YOUR_DOMAIN/health # {"status":"ok"} - Scrape a page:
curl -X POST https://YOUR_DOMAIN/v2/scrape \ -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","formats":["markdown"]}' - Crawl a site. Crawls run on the worker. Start one, then poll it with the
idit returns:curl -X POST https://YOUR_DOMAIN/v2/crawl \ -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","limit":10}' curl https://YOUR_DOMAIN/v2/crawl/CRAWL_ID -H "Authorization: Bearer $FIRECRAWL_API_KEY" - Use the official SDKs. Point them at your URL and key:
# pip install firecrawl-py from firecrawl import Firecrawl app = Firecrawl(api_key="fc-...", api_url="https://YOUR_DOMAIN") doc = app.scrape("https://example.com", formats=["markdown"]) print(doc.markdown)// npm install @mendable/firecrawl-js import Firecrawl from "@mendable/firecrawl-js"; const app = new Firecrawl({ apiKey: "fc-...", apiUrl: "https://YOUR_DOMAIN" }); const doc = await app.scrape("https://example.com", { formats: ["markdown"] }); console.log(doc.markdown); - Optional: open the queue admin UI at
https://YOUR_DOMAIN/admin/{BULL_AUTH_KEY}/queues. TheBULL_AUTH_KEYis on the api service. - Optional: to turn on extract, set
OPENAI_API_KEYon the api service, or setOLLAMA_BASE_URLandMODEL_NAME. The worker reads both values from the api service. Then redeployapiandworker.
Common Use Cases
- Turning web pages and documentation sites into markdown for retrieval-augmented generation (RAG) pipelines and knowledge bases.
- Giving AI agents a scraping and search backend. The official SDKs and the Firecrawl MCP server accept a self-hosted API URL and key.
- Crawling a site on a schedule and storing the pages, without per-page credits. You pay only for the Railway resources you use.
- Getting a site's URL list from its sitemap with
/v2/mapbefore you crawl it selectively. - Extracting structured JSON from pages with your own OpenAI key or your own Ollama models.
Dependencies for Firecrawl Hosting
- Firecrawl API and worker (
ghcr.io/firecrawl/firecrawl) - Playwright rendering service (
ghcr.io/firecrawl/playwright-service) - NuQ Postgres, Postgres 17 with pg_cron (
ghcr.io/firecrawl/nuq-postgres) - Redis and RabbitMQ
- Caddy, as the authenticating gateway
Deployment Dependencies
- Firecrawl source: https://github.com/firecrawl/firecrawl
- Self-hosting guide: https://github.com/firecrawl/firecrawl/blob/main/SELF_HOST.md
- API reference: https://docs.firecrawl.dev/api-reference/introduction
- Container images: https://github.com/orgs/firecrawl/packages
- Firecrawl MCP server: https://github.com/firecrawl/firecrawl-mcp-server
- Caddy: https://caddyserver.com/docs/caddyfile
- Bull Board (the queue UI): https://github.com/felixmosh/bull-board
- Railway private networking: https://docs.railway.com/reference/private-networking
Implementation Details
How clients authenticate. Every request to the public URL must carry the header Authorization: Bearer {FIRECRAWL_API_KEY}. This is the same header the Firecrawl SDKs send when you pass api_key / apiKey. The key must match exactly. A missing or wrong key gets 401 with a JSON error. Three things need no key: GET /health (the API's liveness check, for uptime monitors), GET /healthz (the gateway's own check) and CORS preflight OPTIONS requests. There is one shared key. This template does not provide per-user keys, usage tracking or credits.
Admin routes. The queue UI is at /admin/{BULL_AUTH_KEY}/queues. The /admin/ops/* routes need Authorization: Bearer {BULL_AUTH_KEY}. All other /admin paths return 404.
| Service | Variable | Purpose |
|---|---|---|
| gateway | FIRECRAWL_API_KEY | The API key clients send. Generated as fc- plus 32 hex characters. |
| gateway | FIRECRAWL_API_URL | Your public base URL, for api_url / apiUrl. |
| gateway | CADDYFILE | Gateway rules: key check, admin lock, health routes. |
| api | BULL_AUTH_KEY | Queue admin key. Generated, 32 alphanumeric characters. |
| api | OPENAI_API_KEY | Optional. Enables extract, JSON format and summaries. |
| api | OPENAI_BASE_URL | Optional. An OpenAI-compatible endpoint. The default is https://api.openai.com/v1. |
| api | MODEL_NAME / MODEL_EMBEDDING_NAME | Optional model overrides. |
| api | OLLAMA_BASE_URL | Optional, for example http://ollama.railway.internal:11434/api. When set, Ollama becomes the default provider. Also set MODEL_NAME. |
| worker | NUQ_WORKER_COUNT | Number of parallel scrape job runners for crawls and batch scrapes. The default is 5. |
| playwright-service | MAX_CONCURRENT_PAGES | Number of browser pages open at once. The default is 10. |
| nuq-postgres, redis, rabbitmq | POSTGRES_PASSWORD, REDIS_PASSWORD, RABBITMQ_DEFAULT_PASS | Generated passwords. They are used only on the private network. |
Upgrade notes
- The images track
:latest. To upgrade, redeployapi,workerandplaywright-service. Upstream sometimes changes the process layout. Before you upgrade an instance you depend on, checkSELF_HOST.mdanddocker-compose.yamlin the release. - The worker's start command runs the same processes as upstream's runner (
queue-worker,extract-worker,nuq-worker×NUQ_WORKER_COUNT,nuq-prefetch-worker,nuq-reconciler-worker). If a release adds a process, add it to the start command. nuq-postgres:latestruns Postgres 17 today. If upstream moves it to a new major version, the existing data directory will not start. Before redeployingnuq-postgres, pin the tag, or dump and restore the data. The queue data is mostly short-lived job state.- Postgres starts with
max_wal_size=1GBandmin_wal_size=80MB. These override the 16GB/4GB values that upstream's schema script sets, which could fill a small volume. - To rotate the API key, change
FIRECRAWL_API_KEYon the gateway and redeploy only the gateway. To rotate the admin key, changeBULL_AUTH_KEYon the api and redeployapiandgateway. Keep both keys to letters, digits and dashes, because the gateway config uses them as literal values. - Search uses Firecrawl's built-in DuckDuckGo fallback. To use your own SearXNG instance, set
SEARXNG_ENDPOINTon the api.
Why Deploy Firecrawl on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Firecrawl on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
Template Content
playwright-service
ghcr.io/firecrawl/playwright-service:latestredis
redis:alpinenuq-postgres
ghcr.io/firecrawl/nuq-postgres:latestrabbitmq
rabbitmq:3-managementgateway
caddy:latest
