Install for production
For a public instance, keep ShipLean and PostgreSQL on a private container network, and put a TLS reverse proxy in front of them. The Caddy Compose file, Caddyfile, and environment file together form a standalone example. Point your domain’s DNS record at the host, and allow inbound ports 80 and 443 so that Caddy can obtain a public TLS certificate. Set SHIPLEAN_DOMAIN, POSTGRES_PASSWORD, SHIPLEAN_ADMIN_EMAIL, and SHIPLEAN_ADMIN_PASSWORD in .env before you start it. Set POSTGRES_PASSWORD to a long random password of letters and digits. After you sign in as the first instance admin, remove SHIPLEAN_ADMIN_EMAIL and SHIPLEAN_ADMIN_PASSWORD from .env. The Compose file pins the Caddy address and trusts only that address for forwarded client information. See Caddy’s automatic HTTPS requirements and Caddyfile environment variables.
Configure your proxy
Section titled “Configure your proxy”ShipLean accepts forwarded client address and scheme headers only when the request comes from a trusted proxy. Set SHIPLEAN_TRUSTED_PROXIES to the address or CIDR range that connects to ShipLean. If your proxy supplies the client address in a different header, set SHIPLEAN_FORWARDED_FOR_HEADER to that header name. The default is X-Forwarded-For.
For a direct Caddy-to-ShipLean connection, the example uses Caddy’s container address for SHIPLEAN_TRUSTED_PROXIES. Caddy passes the original Host header and supports WebSocket proxying, which ShipLean uses for live board updates. Do not publish ShipLean’s port directly to the internet. See the Caddy reverse proxy reference for its forwarding and WebSocket behavior.
With nginx, preserve the original Host, and forward the WebSocket upgrade headers. For example, inside the location that proxies to ShipLean:
proxy_pass http://127.0.0.1:8080;proxy_http_version 1.1;proxy_set_header Host $http_host;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;ShipLean must trust the address that nginx connects from. For WebSocket proxying, nginx needs the Upgrade and Connection headers passed explicitly. See nginx’s WebSocket proxying guide.
You can also use Cloudflare Tunnel to connect a private service to Cloudflare, without a publicly routable origin address. Restrict the origin so that only the tunnel can reach ShipLean. When Cloudflare supplies the client address in CF-Connecting-IP, set SHIPLEAN_FORWARDED_FOR_HEADER=CF-Connecting-IP and trust only the address of the tunnel connector. See Cloudflare’s HTTP header reference for CF-Connecting-IP.
Set the instance URL
Section titled “Set the instance URL”In Instance settings, set the base URL to the public HTTPS address that people and agents use to reach ShipLean. Agents’ MCP tokens are bound to this URL. Changing it invalidates that audience. It disconnects every agent, and each agent must connect again.
Back up data
Section titled “Back up data”Back up PostgreSQL and the blob store. Work item data and settings are in PostgreSQL. Attachments and profile photos are in the configured blob store. By default, that is the /data/blobs volume. Otherwise, it is the PostgreSQL or S3 store that the configuration selects. A database backup alone does not include files stored in the blob folder or the S3 bucket.
For the included Compose example, you can create a PostgreSQL dump with:
docker compose exec -T postgres pg_dump -U postgres -d shiplean --format=custom > shiplean.dumpBack up the shiplean-blobs volume with your container host’s volume backup or snapshot procedure. If you store blobs in PostgreSQL or S3, use that store’s backup process instead. To take a consistent backup of both stores, pause writes to ShipLean while you capture them. Keep backup copies off the host, and check periodically that you can restore them.
Upgrade
Section titled “Upgrade”The published image applies the database schema and migrations when it starts. Pull the new image and recreate the app container:
docker compose pull shipleandocker compose up -d shipleanSHIPLEAN_DB_MIGRATE defaults to true. If you set it to false, ShipLean skips startup migrations. Set it to false only when another process applies the required schema and migrations before the app starts. Keep a current database and blob-store backup before you upgrade.
Size the instance
Section titled “Size the instance”No fixed memory limit is published for the container. ShipLean’s search documentation estimates about 1.7 KB of memory per embedded search row in the semantic vector cache, or about 85 MB for 50,000 rows. That figure is a cache estimate, not a container limit. It does not include the app, the database, the model, or other work. Start without a tight memory cap, watch actual use as your data grows, and then set a limit with headroom for your own workload. To reduce memory used by embeddings, set SHIPLEAN_EMBEDDINGS=off. Search then matches words only.