Post

Deploy PocketBase backend with Docker and Traefik

Run PocketBase as a small self-hosted backend for apps, APIs, auth, and file storage.

Deploy PocketBase backend with Docker and Traefik

Run PocketBase as a small self-hosted backend for apps, APIs, auth, and file storage.

This is a standalone service guide. It explains the service in isolation so you can deploy it without copying unrelated parts of another stack.

All domains, emails, usernames, IP addresses, passwords, and tokens in this post are placeholders. Replace them for your own server, but do not publish real secrets or private infrastructure details.


What this service does

Route or access pattern:

1
pocket.example.com

Main components:

1
PocketBase binary/container, pb_data, optional pb_hooks.

Network and port model:

1
Traefik routes HTTPS to PocketBase port 8080; pb_data stores the SQLite app data.

In a Docker homelab, the safest pattern is to keep the application private on Docker networks and let the reverse proxy handle HTTPS traffic.


Folder layout

Use a dedicated folder:

1
2
3
4
5
/home/ubuntu/pocket/
├── docker-compose.yml
├── .env
├── data/              # or service-specific persistent data
└── backups/           # optional local backup destination

Keep .env private. Public documentation should show only placeholders.


Environment file

Example .env values:

[email protected]
ADMIN_PASSWORD=<admin-password>
POCKETBASE_DOMAIN=pocket.example.com

Rules:

  • generate long random passwords and tokens;
  • keep .env out of Git;
  • do not paste production values into public tutorials;
  • rotate exposed credentials immediately if they ever leak.

Compose pattern

A minimal Traefik-aware Compose pattern looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
services:
  pocket:
    image: <service-image>:<version>
    container_name: pocket
    restart: unless-stopped
    env_file:
      - .env
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.pocket.entrypoints=https"
      - "traefik.http.routers.pocket.rule=Host(`pocket.example.com`)"
      - "traefik.http.routers.pocket.tls=true"
      - "traefik.http.routers.pocket.tls.certresolver=cloudflare"
      - "traefik.http.services.pocket.loadbalancer.server.port=<internal-port>"

networks:
  proxy:
    external: true

Adapt image names, volumes, internal ports, and service-specific environment variables for the actual application.


Deployment steps

Create the directory:

1
2
mkdir -p /home/ubuntu/pocket
cd /home/ubuntu/pocket

Create the .env file with placeholder values replaced by your own secrets:

1
2
nano .env
chmod 600 .env

Create or edit docker-compose.yml, then start the service:

1
docker compose up -d

Check status:

1
2
docker compose ps
docker compose logs --tail=100

Verification checklist

Verify the container is running:

1
docker ps --filter name=pocket

Verify Traefik can see the route:

1
docker logs traefik --tail=100

Verify the public route, if the service has one:

1
curl -I https://service.example.com

Expected results vary by service:

  • 200 means the app is reachable;
  • 302 can be correct when authentication redirects to an identity provider;
  • 401 can be correct for APIs that require authentication;
  • 404 usually means the Traefik router rule did not match.

Backup checklist

Back up at least:

1
2
3
/home/ubuntu/pocket/docker-compose.yml
/home/ubuntu/pocket/.env        # private backup only
/home/ubuntu/pocket/data/       # or named Docker volumes

For database-backed services, prefer application-aware dumps in addition to copying files:

1
docker compose exec <database> <dump-command> > backup.sql

Never publish backup archives. They often contain tokens, password hashes, uploads, user data, or private keys.


Common problems

The domain returns 404

Check:

  • the container has traefik.enable=true;
  • the service is attached to the proxy network;
  • the router Host(...) rule matches the exact domain;
  • traefik.docker.network=proxy is set when the container has multiple networks.

The domain returns bad gateway

Traefik found the route but cannot reach the internal app port.

Check the application logs and confirm the internal port used by:

1
traefik.http.services.<service>.loadbalancer.server.port

The service starts but data disappears after restart

The persistent directory or Docker volume is missing. Add a named volume or a bind mount for the service data before using it seriously.

Authentication loops or redirects fail

Check the public URL, trusted proxy headers, cookie domain, and whether the app knows it is behind HTTPS.


Security notes

  • Keep admin dashboards behind authentication or private networks.
  • Do not expose databases, caches, or admin APIs directly to the internet.
  • Use least-privilege API tokens.
  • Prefer internal Docker networks for dependencies.
  • Keep public docs generic: use example.com, <token>, <password>, and documentation IP ranges.

Service documentation map

This post is part of the standalone homelab service documentation series. Use these guides together when building the full stack:

This post is licensed under CC BY 4.0 by the author.