Introduction
Docker provides a consistent, reproducible way to deploy Paperclip without worrying about host system dependencies. Whether you are running a quick local test or deploying to a cloud server, Docker containers ensure the same behavior everywhere. This lesson covers the Docker run command, docker-compose setup, and volume persistence.
Key Concepts
- Docker container: An isolated runtime that packages Paperclip with all its dependencies.
- Port 3100: The default port Paperclip listens on inside the container, mapped to the host.
- PAPERCLIP_HOME: Environment variable that sets the data directory inside the container.
- Volume mount: Persists Paperclip's data directory outside the container so data survives container restarts.
Real World Context
A DevOps engineer needs to deploy Paperclip on a cloud VM for the team. Installing Node.js, pnpm, and managing system dependencies on a production server is fragile and hard to reproduce. A single docker run command with a volume mount gives them a running instance in seconds, with data persistence and easy upgrades — just pull the new image and restart.
Deep Dive
The quickest way to run Paperclip in Docker is a single docker run command.
bashdocker run --name paperclip \ -p 3100:3100 \ -e HOST=0.0.0.0 \ -e PAPERCLIP_HOME=/paperclip \ -v "$(pwd)/data:/paperclip" \ paperclip-local
This command maps port 3100 from the container to the host, sets the HOST environment variable to 0.0.0.0 so the server accepts connections from outside the container, configures PAPERCLIP_HOME to /paperclip inside the container, and mounts a local data directory to persist all Paperclip data including the PGlite database.
The volume mount at -v "$(pwd)/data:/paperclip" is critical. Without it, all data is lost when the container stops. The mounted directory stores the PGlite database, configuration files, and any local file storage assets.
For more complex deployments, use docker-compose to orchestrate Paperclip with an external PostgreSQL database.
yaml# docker-compose.yml version: '3.8' services: paperclip: image: paperclip-local ports: - "3100:3100" environment: HOST: 0.0.0.0 PAPERCLIP_HOME: /paperclip DATABASE_URL: postgresql://paperclip:secret@db:5432/paperclip volumes: - paperclip-data:/paperclip depends_on: db: condition: service_healthy db: image: postgres:17 environment: POSTGRES_USER: paperclip POSTGRES_PASSWORD: secret POSTGRES_DB: paperclip volumes: - pg-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U paperclip"] interval: 5s timeout: 5s retries: 5 volumes: paperclip-data: pg-data:
This compose file starts both Paperclip and PostgreSQL 17, with a health check ensuring the database is ready before Paperclip starts. Named volumes persist data across container restarts and upgrades.
Start the stack with a single command.
bashdocker compose up -d
The -d flag runs containers in the background. Access the UI at http://localhost:3100.
Common Pitfalls
- Forgetting the volume mount — Without
-v, all data lives inside the container and is destroyed when the container is removed. Always mount a volume for PAPERCLIP_HOME. - Not setting HOST=0.0.0.0 — By default, Paperclip binds to localhost. Inside a Docker container, localhost means the container itself, not the host machine. Set
HOST=0.0.0.0to accept connections forwarded from the Docker port mapping.
Best Practices
- Use named volumes in production — Named Docker volumes (
paperclip-data:) are managed by Docker and survivedocker compose down. Bind mounts (./data:/paperclip) are easier for development but riskier in production. - Add health checks for dependent services — The
depends_onwithcondition: service_healthyensures Paperclip does not start before PostgreSQL is ready, preventing startup crashes.
Summary
docker runwith port mapping, HOST=0.0.0.0, and a volume mount is the quickest Docker deployment.- PAPERCLIP_HOME sets the data directory inside the container.
- Use docker-compose for multi-service deployments with external PostgreSQL.
- Always mount volumes to persist data across container restarts.
- Set HOST=0.0.0.0 so the containerized server accepts external connections.
Code Examples
docker run --name paperclip \
-p 3100:3100 \
-e HOST=0.0.0.0 \
-e PAPERCLIP_HOME=/paperclip \
-v "$(pwd)/data:/paperclip" \
paperclip-local