Self-Hosting PocketBase with Docker Compose

What Is PocketBase?

PocketBase is a self-hosted backend in a single binary. It bundles a SQLite database, realtime subscriptions, user authentication (password, OAuth2, OTP), file storage, and a full admin dashboard. You get a Firebase-like backend without vendor lock-in, external dependencies, or monthly bills. It’s written in Go, weighs about 15 MB, and can run on a Raspberry Pi. Official site.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 256 MB of free RAM (PocketBase uses ~15-30 MB idle)
  • Understanding: PocketBase is pre-1.0 software (v0.36.x) — breaking changes can occur between versions

Docker Compose Configuration

PocketBase doesn’t have an official Docker image. The recommended approach is building from the official Dockerfile. Create a project directory:

mkdir pocketbase && cd pocketbase

Create a Dockerfile:

FROM alpine:3.21

ARG PB_VERSION=0.36.5

RUN apk add --no-cache \
    unzip \
    ca-certificates

ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip
RUN unzip /tmp/pb.zip -d /pb/ && \
    rm /tmp/pb.zip

EXPOSE 8090

CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8090"]

Create docker-compose.yml:

services:
  pocketbase:
    build:
      context: .
      args:
        PB_VERSION: "0.36.5"
    container_name: pocketbase
    restart: unless-stopped
    ports:
      - "8090:8090"
    volumes:
      - pocketbase-data:/pb/pb_data       # SQLite database, uploaded files, backups
      # - ./pb_hooks:/pb/pb_hooks         # Uncomment for JavaScript hooks
      # - ./pb_migrations:/pb/pb_migrations # Uncomment for schema migrations
    environment:
      - GOMEMLIMIT=512MiB                 # Prevents OOM in constrained environments
    ulimits:
      nofile:
        soft: 4096
        hard: 4096

volumes:
  pocketbase-data:

Build and start:

docker compose up -d --build

Initial Setup

The admin dashboard is at http://your-server:8090/_/.

Create a superuser account via CLI (the recommended approach since v0.23):

docker exec -it pocketbase /pb/pocketbase superuser upsert [email protected] YourSecurePassword123

Log in to the dashboard with these credentials.

Create Your First Collection

Collections are PocketBase’s version of database tables.

  1. Click New collection in the dashboard
  2. Name it (e.g., “posts”)
  3. Add fields — PocketBase supports text, number, bool, email, URL, date, file, relation, JSON, select, and GeoPoint fields
  4. Set API Rules to control who can read, create, update, and delete records
  5. Save — your REST API is immediately available at /api/collections/posts/records

Key Features

FeatureDetails
DatabaseEmbedded SQLite with WAL mode (concurrent reads, serialized writes)
AuthenticationPassword, OAuth2 (Google, GitHub, Microsoft, Apple, Discord, etc.), OTP, MFA
RealtimeServer-Sent Events for live data — subscribe to collection or record changes
File storageLocal filesystem (default) or S3-compatible (AWS, MinIO, Wasabi, DigitalOcean Spaces)
Admin dashboardFull web UI for managing collections, records, settings, backups, and logs
REST APICRUD with filtering, sorting, pagination, field selection, relation expansion, batch operations
API rulesPer-collection access control with filter expressions
JavaScript hooksExtend PocketBase with JS files in pb_hooks/
Auto HTTPSPass a domain to pocketbase serve example.com for automatic Let’s Encrypt
BackupsBuilt-in dashboard backup creates ZIP snapshots
Rate limitingBuilt-in (v0.23.0+), configurable via dashboard

Configuration

S3 File Storage

Switch from local filesystem to S3-compatible storage via the admin dashboard:

  1. Go to SettingsFiles storage
  2. Select S3 and enter your credentials
  3. Existing local files are NOT migrated automatically

SMTP for Email

Configure email sending for password resets and verification:

  1. Go to SettingsMail settings
  2. Enter your SMTP server details
  3. Test with the built-in test button

Encryption

Encrypt sensitive settings (SMTP passwords, S3 keys) stored in the database:

environment:
  - PB_ENCRYPTION_KEY=your-random-32-character-string-here

Then start PocketBase with --encryptionEnv=PB_ENCRYPTION_KEY.

JavaScript Hooks

Extend PocketBase’s behavior with JavaScript files:

mkdir pb_hooks

Create pb_hooks/main.pb.js:

onRecordAfterCreateSuccess((e) => {
    console.log("New record created:", e.record.id)
}, "posts")

Mount the hooks directory in your Compose file and restart.

What PocketBase Replaces

Cloud ServicePocketBase Equivalent
Firebase FirestoreCollections + REST API
Firebase AuthBuilt-in auth (password, OAuth2, OTP)
Firebase StorageFile fields + local or S3 storage
Firebase Realtime DatabaseSSE subscriptions
SupabaseFull backend (minus edge functions)
AirtableCollections with the admin dashboard

Reverse Proxy

PocketBase serves everything on a single port. Standard reverse proxy configuration works:

location / {
    proxy_pass http://127.0.0.1:8090;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection '';
    proxy_buffering off;                # Required for SSE realtime
    client_max_body_size 50M;           # Adjust for file uploads
}

See Reverse Proxy Setup.

Backup

PocketBase stores everything in pb_data/:

# Use the built-in backup from the admin dashboard
# Or back up the volume directly:
docker compose stop pocketbase
docker run --rm -v pocketbase-data:/data -v $(pwd):/backup alpine \
  tar czf /backup/pocketbase-backup-$(date +%Y%m%d).tar.gz /data
docker compose start pocketbase

For databases over 2 GB, use sqlite3 .backup instead of the built-in ZIP backup — it’s faster and produces a consistent snapshot. See Backup Strategy.

Troubleshooting

”database is locked” errors

Symptom: Requests fail with SQLite busy/locked errors. Fix: Never store pb_data on network-attached storage (NFS, SMB, Azure Files). SQLite requires proper file locking that network filesystems don’t provide. Use local block storage or Docker named volumes backed by local disk.

Superuser creation token not visible

Symptom: First run prints a secure link to stderr, but you can’t see it in Docker. Fix: Check container logs with docker logs pocketbase. Or skip the link entirely and create a superuser via CLI: docker exec -it pocketbase /pb/pocketbase superuser upsert email password.

File uploads fail with large files

Symptom: Uploads over 5 MB fail. Fix: The default upload limit is 5 MB per file. Adjust in the admin dashboard under collection settings → file field → Max file size. Also increase client_max_body_size in your reverse proxy.

High memory usage under load

Symptom: Container memory grows beyond expected limits. Fix: Set GOMEMLIMIT=512MiB (or appropriate for your environment) to force Go’s garbage collector to be more aggressive. Also reduce log retention in Settings → Logs.

Container file descriptor limit

Symptom: Errors about “too many open files” with many realtime connections. Fix: Set ulimits.nofile in your Compose file to at least 4096. The default 1024 is insufficient for applications with many concurrent SSE connections.

Resource Requirements

  • RAM: ~15-30 MB idle, ~50-100 MB under load
  • CPU: Minimal — single core sufficient
  • Disk: 15 MB binary. Database and files grow with usage. 1 GB minimum recommended.
  • Limitation: Single-writer SQLite. Cannot horizontally scale — one instance only.

Verdict

PocketBase is the fastest way to self-host a backend. For personal projects, internal tools, and small-to-medium apps, it replaces Firebase, Supabase, and Airtable with zero monthly cost and zero external dependencies. The admin dashboard is polished, the API is well-designed, and the realtime support works out of the box.

The limitations are real: pre-1.0 software (expect breaking changes), SQLite-only (no horizontal scaling), and no official Docker image. For production applications at scale, look at Appwrite or Supabase. For everything else, PocketBase is exceptional.