Skip to main content
This walkthrough takes an empty virtual machine to PostQueen running at https://postqueen.example.com. Every command is written out. Plan on about thirty minutes, most of it downloads.

What you need

Replace postqueen.example.com with your own name everywhere on this page.

Install

1

Create the server

Order an Ubuntu 24.04 machine from any provider. Note its public IP address, for example 203.0.113.42, and the SSH login it gives you.
2

Point the domain at it

Where your domain’s DNS is managed, add an A record: name postqueen (or @ for the bare domain), value the server’s IP address. Then check from your own computer:
The command prints the server’s IP address. The certificate step fails until it does.
3

Connect and install Docker

Use the username your provider gave you if it is not root. The last command prints the Compose version, which has to be v2.24 or newer. Every command from here runs on the server.
4

Open only SSH and the web ports

Allow OpenSSH before you enable the firewall, or it locks you out of the server.
5

Clone the Compose repository

Stay in this folder. It holds docker-compose.yaml and the dynamicconfig folder Temporal reads at start.
6

Bind port 4007 to the server itself

Docker publishes container ports past UFW, so the rules above do not close port 4007. In docker-compose.yaml, change the postqueen service’s port line:
PostQueen then answers only on the server, where the reverse proxy reaches it, and the outside world sees only ports 80 and 443. Keeping the original "4007:5000" leaves PostQueen reachable over plain HTTP on port 4007 from anywhere.
7

Write the .env file

Put your own domain in the three addresses before you run it. Keep /api on the last one and leave off trailing slashes. Do not add NOT_SECURED: the site runs on HTTPS.
Keep both keys once set. JWT_SECRET signs sessions, so changing it signs everyone out. ENCRYPTION_KEY encrypts the API key, the stored credentials of networks such as Bluesky and WordPress, and other secrets, so changing it without PREVIOUS_ENCRYPTION_KEY makes those unreadable. Setting ENCRYPTION_KEY now, before there is data, is what lets you rotate JWT_SECRET later. See Configuration reference.
8

Pin the image

The Compose file uses ghcr.io/gkhankinay/postqueen-app:latest, which moves with every release. Pin a release tag so an upgrade happens when you choose:
Take the newest tag from the app’s tags or the image package, written with its v. The GitHub Releases page is not kept current, so do not take the version from there. Later, only ever move the tag forward: Backups and upgrades explains why.
9

Start PostQueen

Wait for Backend started successfully on port 3000, then press Ctrl+C. Read the lines just after it: the backend checks its settings and prints each problem as a Configuration issue, but keeps running either way. Then check that it answers on the server:
HTTP/1.1 200 OK.
10

Add HTTPS

Put a reverse proxy in front of port 4007. With Caddy it is three lines and the certificate renews itself: follow Domain and HTTPS, then come back when https://postqueen.example.com loads.Nginx and Traefik work too.
11

Create your account, then close sign-up

Open https://postqueen.example.com and sign up. That first account owns the install.Everyone who should have an account on this install has to sign up now, before you close it. Then add this line to .env:
Recreate the app container so it reads the new values. A plain docker restart or docker compose restart keeps the old container and its old environment.In the folder that holds docker-compose.yaml, recreate only the postqueen service:
The database, Redis and Temporal keep running. Avoid docker compose down for a settings change: on a host that runs other Compose services in the same project, it stops them too. On Kubernetes, see Kubernetes with Helm.
Closing sign-up also blocks invitations for new people. Existing accounts sign in as before, and you can still invite someone who already has an account here. A person without one cannot create it from an invite while this is set. People who sign in through your own single sign-on provider are the exception: they still get an account.
PostQueen runs on your domain, over HTTPS, and nobody new can sign up.

Connect channels

Eight networks need no setup: Bluesky, DEV, Hashnode, Lemmy, Listmonk, Nostr and WordPress take a key or login in the connect form, and Moltbook registers an agent. For the others, register a developer app with the network, put its keys in .env, recreate the postqueen container, then open Channels and choose Add Channel. Channel developer apps lists each network’s variables, redirect URI and setup page.

If something is not right

Work outward from the container. If curl -I http://localhost:4007 fails on the server, PostQueen is not up: docker compose logs postqueen says why. If it works but the domain does not, check DNS with dig +short postqueen.example.com and the proxy’s own log.
FRONTEND_URL has to be exactly the address in the browser, with https:// and no trailing slash. The backend accepts requests only from that address and MAIN_URL. Look for the backend’s warnings:
Do not set NOT_SECURED=true to work around it on a public server.
Each network sends the browser back to FRONTEND_URL + /integrations/social/ + the network’s name. If FRONTEND_URL changed after you registered the app, update the redirect URI in the network’s console. A missing or wrong key shows up as an error page on the network’s side, not in PostQueen.
Usually memory. docker stats shows usage, and docker compose logs postqueen shows why it stopped. The stack needs about 4 GB.
JWT_SECRET changed. Put the old value back, or accept that everyone signs in again. Self-hosting troubleshooting covers what else a changed key breaks.

Next steps

Set up email

Without it, password resets send nothing.

Back up your data

Which volumes hold data you cannot rebuild, and how to restore them.

Channel developer apps

Each network’s app, keys and redirect URI.

Uploads and storage

Local disk or Cloudflare R2, and what each asks of you.
Last modified on September 23, 2026