Skip to main content

Self-Hosting Web Scrapers: Complete Infrastructure Guide for 2026

· 7 min read
Yassine El Haddad
Software Developer & Automation Specialist

I build production AI agents, web scrapers, and automation pipelines. Most of what I publish here comes from the actual problems they run into: proxies that get banned, anti-bot stacks that fingerprint your client, RAG that drifts when the underlying data moves. Stack: Python, TypeScript, Go, FastAPI, LangChain, Crawlee, Playwright, deployed on AWS, GCP, and Cloudflare.

Self-hosting web scrapers gives you full control: custom stack, sensitive data stays on your infra, and at high volume you can optimize cost. This guide covers when self-hosting makes sense vs using Apify, infrastructure components (VPS, proxies, queue, storage, monitoring), Docker Compose setup with Crawlee, scaling strategies, and a cost comparison. Run on a Liquid Web VPS for reliable hosting with SSD storage and managed support.

When to Self-Host vs Use Apify

FactorSelf-HostApify
Data volumeHigh (millions of pages) — cost optimizesLower–medium — pay-per-run scales simply
Sensitive dataKeep on your infraEvaluate data residency; Apify is cloud
Custom stackFull control (Crawlee, Scrapy, etc.)Constrained to Actor model
MaintenanceYou own infra, monitoring, updatesApify handles runtime and scaling
Time to productionLonger setupFaster: pick Actor, run

Self-host when: You have high, predictable volume; need data sovereignty; or have a mature DevOps team. Use Apify when: You want speed, no infra management, or access to the Actor marketplace.

Infrastructure Components

ComponentRoleOptions
VPS / dedicated serverCompute for crawlersLiquid Web, DigitalOcean, Hetzner
Proxy poolAnti-bot bypass, IP rotationBright Data, IPRoyal, Oxylabs
Request queuePersist URLs, retriesRedis, BullMQ, Crawlee RequestQueue (in-memory or Redis)
StorageStore extracted dataPostgreSQL, MongoDB, S3, MinIO
MonitoringMetrics, alertsPrometheus, Grafana, PagerDuty, Slack

VPS Selection for Playwright Scrapers

Playwright and Crawlee with browser automation are memory-heavy. Minimum specs:

SpecMinimumRecommended
RAM8 GB16 GB for 2–3 concurrent browsers
vCPU48 for higher concurrency
Storage50 GB SSD100+ GB for datasets
OSUbuntu 22.04 / 24.04LTS with security updates

Liquid Web VPS offers 8 GB RAM plans with SSD. See Liquid Web VPS Scraping Setup for step-by-step provisioning.

Docker Compose Stack: Redis + Crawlee + PostgreSQL

# docker-compose.yml
services:
redis:
image: redis:7-alpine
ports: ["6379:6379"]
volumes: [redis_data:/data]

postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: scraped
POSTGRES_USER: scraper
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes: [pg_data:/var/lib/postgresql/data]

workers:
build: ./workers
environment:
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://scraper:${DB_PASSWORD}@postgres:5432/scraped
PROXY_URL: ${BRIGHT_DATA_PROXY}
depends_on: [redis, postgres]
deploy:
replicas: 2
restart: unless-stopped

volumes:
redis_data: {}
pg_data: {}

Workers run Crawlee with Playwright. Redis backs the RequestQueue for persistence. PostgreSQL stores extracted items. See Docker Compose Production Guide for secrets, health checks, and limits.

Proxy Integration

For anti-bot targets, use residential proxies. Bright Data and IPRoyal provide HTTP/SOCKS5 gateways. Configure Crawlee:

const proxyConfiguration = new ProxyConfiguration({
proxyUrls: [process.env.PROXY_URL],
});
const crawler = new PlaywrightCrawler({
proxyConfiguration,
// ...
});

Or use Apify Proxy as a custom proxy in your self-hosted Crawlee—gives you Apify's proxy pool without running on Apify platform.

Monitoring and Alerting

MetricToolAlert when
Crawl ratePrometheus + GrafanaThroughput drops > 50%
Error rateCrawler logs, Prometheus5xx or block rate > 10%
Queue depthRedis INFOQueue grows unbounded
Worker healthDocker / systemdWorker exits or OOM

Export Crawlee metrics (requests/min, failed count) to Prometheus. Alert to PagerDuty or Slack when thresholds are breached.

Scaling Strategy

ApproachWhenHow
VerticalSingle bottleneckUpgrade VPS (more RAM, CPU)
HorizontalNeed more throughputAdd worker replicas; share Redis queue
ShardingVery large queuesPartition URLs by domain or hash; multiple queues

Start with 1–2 workers. Scale horizontally when queue depth grows and CPU is underutilized.

Cost Comparison: Self-Hosted vs Apify

Rough estimates per million pages crawled (with JS rendering):

CostSelf-Hosted (8 GB VPS + proxies)Apify (pay-per-run)
Compute~$30–50/mo (VPS)Included in platform
Proxies$50–150/mo (residential)Apify Proxy or custom
Total~$80–200/mo fixed~$0.25–1.00 per 1K pages → $250–1000/mo at 1M

At low volume (< 100K pages/mo), Apify is often cheaper. At high volume (> 1M/mo), self-hosting can save 50–70% if you optimize.

Crawlee Worker Example

A minimal Crawlee worker for the Docker stack:

// workers/src/main.ts
import { PlaywrightCrawler } from 'crawlee';
import { Client } from 'pg';

const crawler = new PlaywrightCrawler({
maxConcurrency: 2,
requestHandler: async ({ page, request }) => {
const title = await page.title();
const price = await page.$eval('.price', el => el.textContent).catch(() => null);
const pg = new Client(process.env.DATABASE_URL);
await pg.connect();
await pg.query(
'INSERT INTO products (url, title, price) VALUES ($1, $2, $3)',
[request.url, title, price]
);
await pg.end();
},
});

const urls = process.env.START_URLS?.split(',') || [];
await crawler.run(urls);

Add BullMQ or similar to pull URLs from Redis. Run with docker compose up workers after building the image.

Cron and Scheduling

For recurring runs, use cron or a task scheduler: 0 2 * * * cd /app/workers && node dist/main.js runs daily at 2 AM. Or use a job queue (BullMQ, Celery) to enqueue crawl jobs on a schedule. For hybrid control, trigger self-hosted workers via webhooks from Apify Schedules.

Data Pipeline and Backup

Extract data flows: Crawlee → PostgreSQL or Redis → downstream ETL. Use connection pooling and batch inserts. For disaster recovery, run daily pg_dump, Redis RDB snapshots, and replicate extracted data to S3. See Docker Compose Production Guide for container redundancy.

Security Considerations

Self-hosted scrapers handle outbound traffic and stored data. Harden the stack: (1) run workers as non-root; (2) store proxy and DB credentials in secrets (Docker secrets, env files not in git); (3) use TLS for DB connections; (4) restrict firewall to required ports only; (5) keep OS and dependencies updated. See VPS Security Hardening Checklist for server-level hardening.

Worker Configuration Best Practices

  • maxConcurrency: Start at 2–3 for Playwright; increase only if CPU/RAM allow.
  • navigationTimeoutSecs: 30–60 for slow targets; avoid infinite waits.
  • maxRequestsPerCrawl: Cap runs to control cost; enqueue more via scheduler.
  • requestHandler: Keep logic focused; offload heavy processing to a queue.

Failure Modes and Mitigation

FailureMitigation
Worker crashHealth checks, auto-restart, redundant replicas
IP banResidential proxies, session rotation, rate limiting
Target site redesignFlexible selectors, smoke tests, AI extraction fallback
Storage fullRetention policies, S3 lifecycle, archive old data
Redis / DB downReplication, backups, failover

Apply patterns from Apify Error Handling: retries, session pools, failed-request handling.

Apify Affiliate Banner 728x90Apify Affiliate Banner 728x90Apify Affiliate Banner 300x50Apify Affiliate Banner 300x50
Start small

Begin with a single VPS, one worker, and a small proxy budget. Validate throughput and cost. Scale when you hit limits. Liquid Web VPS · Bright Data proxies

Frequently Asked Questions

Minimum 8 GB RAM, 4 vCPU. Each headless browser uses ~300–500 MB. 16 GB allows 2–3 concurrent browsers comfortably. SSD storage recommended.

Yes. Configure Apify Proxy as a custom proxy URL in Crawlee. You pay for Apify Proxy usage while running workers on your own infra.

Use residential proxies (Bright Data, IPRoyal). Rotate sessions. Add delays between requests. Respect robots.txt and rate limits.

Often yes at > 1M pages/month. Fixed VPS + proxy costs can undercut pay-per-run. Below ~100K pages/month, Apify is usually simpler and competitive.

Track crawl rate, error rate, queue depth, worker health. Use Prometheus + Grafana. Alert to Slack/PagerDuty when throughput drops or errors spike.

Use Redis or another external store. Crawlee supports RequestQueue with Redis. Configure storage in crawler options so queue survives worker restarts.

Common mistakes and fixes

Worker crashes under load

Increase RAM (8GB+ for Playwright). Lower maxConcurrency. Add health checks and auto-restart. Check for memory leaks.

IP banned by target site

Add residential proxies (Bright Data, IPRoyal). Rotate sessions. Respect rate limits and robots.txt.

Scraper breaks after site redesign

Monitor for 404s and empty datasets. Use flexible selectors. Add smoke tests. Consider AI extraction for variable layouts.