# Deploy: Docker The container runs the Node server with SQLite and filesystem blobs on a volume. It is the shortest path to a PDS on a host you control. ## Pull the image [atcr.io](https://atcr.io) publishes the images. It is a container registry built on atproto, so the image carries the same handle as everything else here. A pull needs an atproto account. Log in once with your handle and an app password. ```bash docker login atcr.io # handle + app password ``` ## Run it ```bash # Generate the signing secret once and keep it. openssl rand -hex 32 > jwt-secret docker run -d \ -p 3000:3000 \ -v pds-data:/data \ -e PDS_HOSTNAME=your-hostname.com \ -e JWT_SECRET="$(cat jwt-secret)" \ -e PDS_PASSWORD='your account password' \ atcr.io/chadtmiller.com/pds.js:latest ``` `PDS_HOSTNAME`, `JWT_SECRET` and `PDS_PASSWORD` are required, and the container exits without them. See [configuration](configuration.md) for the reason, and for every optional variable. The container writes its data to the `/data` volume. Generate that secret once, not per run. It signs session tokens, so a fresh secret on every restart signs out every user. The image targets `linux/amd64`. On arm64 it runs under emulation. ## Finish the setup Terminate TLS in front of the container with nginx or Caddy. Point `your-hostname.com` at it. Then register the DID with the PLC directory. Run this once, from a checkout of the repository, after the PDS answers at its public URL: ```bash npm run setup -- --pds https://your-hostname.com ``` ## Build it yourself ```bash docker build -t pds.js . ``` The build takes `docker/server.js` as its entrypoint. That file composes `@pdsjs/node` from the environment, the same way `examples/node/index.js` does.