Self-host LibreChat for your own ChatGPT-style app
Follow this on your own server. Start free, no card needed
LibreChat is an open-source, ChatGPT-style web interface that talks to OpenAI, Anthropic, Google and dozens of other model providers (or a local one) through your own API keys, instead of putting your conversations through a third party’s own chat product. The one thing it needs that doesn’t fit Railyard’s usual Postgres or Redis add-ons is MongoDB, which is where most self-host attempts go sideways. By the end of this guide you’ll have LibreChat and MongoDB running together behind HTTPS, with real generated secrets instead of the defaults, and a backup you can restore from.
What you’ll need
- A server with Docker and the Compose plugin. A Hetzner CX23 (2 vCPU, 4 GB RAM, 40 GB NVMe, €5.99/month excl. VAT) runs LibreChat and MongoDB comfortably, since the actual model inference happens on the provider’s servers, not yours.
- A domain or subdomain pointed at the server’s IP address.
- At least one model provider API key (OpenAI, Anthropic, or any other LibreChat supports), added after the app is running.
- SSH access to the server.
Step 1: Generate the real secrets
LibreChat ships with placeholder values for its JWT and credential-encryption secrets that work for a local trial but are not safe to run with in production. Four values need real, unique data: a JWT secret, a JWT refresh secret, a credentials encryption key, and its initialization vector. The last two have exact length requirements the others don’t, CREDS_KEY has to be a 32-byte key (64 hex characters), and CREDS_IV exactly a 16-byte IV (32 hex characters), or LibreChat’s own AES-CBC encryption throws algorithm.iv must contain exactly 16 bytes on startup:
openssl rand -hex 32 # JWT_SECRET
openssl rand -hex 32 # JWT_REFRESH_SECRET
openssl rand -hex 32 # CREDS_KEY (32 bytes)
openssl rand -hex 16 # CREDS_IV (16 bytes)
openssl rand -hex 24 # MONGO_PASSWORD
mkdir -p /opt/librechat
cat > /opt/librechat/.env <<'EOF'
JWT_SECRET=paste-the-first-value-here
JWT_REFRESH_SECRET=paste-the-second-value-here
CREDS_KEY=paste-the-third-value-here
CREDS_IV=paste-the-fourth-value-here
MONGO_PASSWORD=paste-the-fifth-value-here
EOF
chmod 600 /opt/librechat/.env
Step 2: Write the Compose file
services:
librechat:
image: ghcr.io/danny-avila/librechat:v0.8.7
restart: unless-stopped
env_file: .env
depends_on:
- mongo
environment:
MONGO_URI: mongodb://librechat:${MONGO_PASSWORD}@mongo:27017/LibreChat?authSource=admin
DOMAIN_CLIENT: https://chat.yourdomain.com
DOMAIN_SERVER: https://chat.yourdomain.com
ALLOW_REGISTRATION: "true"
volumes:
- librechat_uploads:/app/uploads
expose:
- "3080"
mongo:
image: mongo:7
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: librechat
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
volumes:
- librechat_mongo_data:/data/db
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
depends_on:
- librechat
volumes:
librechat_uploads:
librechat_mongo_data:
caddy_data:
caddy_config:
This guide pins v0.8.7, the current stable release as of writing. MONGO_URI carries the username and password MongoDB was initialized with in Step 1, along with authSource=admin, since the root user is created in the admin database, not LibreChat. DOMAIN_CLIENT and DOMAIN_SERVER both need the exact HTTPS URL users will reach the app at; LibreChat uses them to build cookies and CORS rules, so a mismatch here shows up as a confusing login failure rather than an obvious config error. ALLOW_REGISTRATION defaults to true in the upstream image, and matters here because LibreChat has no other built-in way to create the first account, social login is off by default too, so this isn’t optional until Step 4.
Check the file parses:
docker compose config
Step 3: Point DNS, add Caddy, start the stack
chat.yourdomain.com {
reverse_proxy librechat:3080
}
docker compose up -d
docker compose ps
curl -I https://chat.yourdomain.com
You should see both services Up and the curl return HTTP/2 200 with a valid certificate.
Step 4: Create your account, then lock the door
Visit https://chat.yourdomain.com, register through the normal sign-up form, and confirm you can log in. Once every account you need exists, turn registration off:
environment:
ALLOW_REGISTRATION: "false"
docker compose up -d librechat
Step 5: Add a model provider
LibreChat itself never ships with a model API key; it’s a client for providers you bring yourself. Add your key as an environment variable, OpenAI as an example:
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY}
Add OPENAI_API_KEY=your-real-key to .env, then docker compose up -d librechat again. Open the app, pick the provider from the model dropdown, and send a message. You should get a real response back, not an error about a missing or invalid key.
Step 6: Back up MongoDB and uploads
Conversations, accounts and encrypted credentials all live in MongoDB; uploaded files live on the librechat_uploads volume.
cat > /opt/librechat/backup.sh <<'EOF'
#!/bin/sh
cd /opt/librechat
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
docker compose exec -T mongo mongodump --authenticationDatabase admin \
-u librechat -p "${MONGO_PASSWORD}" --db LibreChat --archive --gzip > backups/mongo-$TIMESTAMP.archive.gz
find backups -mtime +14 -delete
EOF
mkdir -p /opt/librechat/backups
chmod +x /opt/librechat/backup.sh
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/librechat/backup.sh") | crontab -
Run it once by hand and check it worked: ./backup.sh && ls -lh backups. You should see a dated .archive.gz file. Restoring is mongorestore --authenticationDatabase admin -u librechat -p "$MONGO_PASSWORD" --archive=path/to/file --gzip, run the same way through docker compose exec. Copy backups off the server; losing both the live MongoDB volume and the only backup of it means every conversation and saved credential is gone.
Step 7: Upgrade
docker compose pull librechat
docker compose up -d librechat
LibreChat runs its own data migrations against MongoDB automatically on startup where needed. Check the release notes for the version you’re moving to before a multi-version jump, since a breaking change to the credential encryption scheme would be the one category worth reading about first.
The shortcut: do it with Railyard
Everything above, MongoDB as the one datastore LibreChat genuinely can’t share with Railyard’s Postgres or Redis add-ons, the JWT and credential secrets generated instead of left at defaults, the uploads volume, is also what Railyard’s LibreChat stack template sets up for you. Connect a server, then pick LibreChat in the templates catalog: app.railyard.run/deploy?stack=librechat. Railyard generates JWT_SECRET, JWT_REFRESH_SECRET, CREDS_KEY and the 16-byte CREDS_IV for you at the correct lengths, wires MongoDB’s connection string in automatically, and issues HTTPS for your domain; you still add your own model provider key afterward, the same as Step 5 above.
See deploy with a button and databases and backups for how templates and persistent data work on the platform more generally.
Troubleshooting
Login works but nothing seems to persist between restarts. Confirm librechat_mongo_data is a real named volume in docker compose ps -a output, not an anonymous one that got pruned; this usually traces back to an earlier docker compose down -v run by accident, which removes volumes along with containers.
algorithm.iv must contain exactly 16 bytes on startup. CREDS_IV wasn’t generated at exactly 16 bytes (32 hex characters). Re-run openssl rand -hex 16 from Step 1 and check the value in .env is exactly 32 characters long, not truncated or padded.
Sign-up form returns a 403. ALLOW_REGISTRATION is false and no accounts exist yet, a chicken-and-egg problem if you turned it off too early. Set it back to true, create the accounts you need, then turn it off again as in Step 4.
The model dropdown shows a provider but every message fails. The API key for that provider either isn’t set, is invalid, or ran out of credit on the provider’s own side; check docker compose logs librechat for the specific upstream error, LibreChat generally passes the provider’s own message through.
HTTPS not issuing. docker compose logs caddy showing repeated ACME errors almost always means DNS from Step 3 hasn’t propagated or points at the wrong IP.
FAQ
Can I run more than one model provider at once? Yes, add as many provider API keys as environment variables as you want; users pick which model to use per conversation from the same dropdown.
Does LibreChat store my conversations with the model provider? No, the provider only sees the request you send it; LibreChat stores the conversation history itself in your own MongoDB, the provider isn’t a second copy of your data.
Can I run a local model instead of a hosted API? Yes, LibreChat supports any OpenAI-compatible endpoint, including local inference servers, pointed at through a custom endpoint configuration rather than a provider API key.
Why MongoDB specifically, when everything else on Railyard is Postgres or Redis? LibreChat’s own schema and query patterns are built around MongoDB’s document model from the start; it isn’t a choice this guide or Railyard makes, it’s what the upstream project requires.
What happens if I lose the server without a backup? Every conversation, account and saved credential is gone; there’s no recovery path into MongoDB data that was never backed up elsewhere, which is why Step 6 isn’t optional in practice.
Once the real secrets are in place and registration is locked down, a self-hosted LibreChat mostly disappears into the background. The ongoing work is the backup habit from Step 6 and adding whichever model provider you actually want to use.
Why people pick Railyard for this
- Your own cloud account. Deploy to DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, or any Linux server over SSH, billed directly by your provider with no markup.
- One flat price per team. Free is free forever: one server plus a database server, three apps, no card. Pro is $19 a month for up to five servers and unlimited apps. Team is $49 a month with unlimited servers. No per-app, per-deploy, per-seat or per-gigabyte charges.
- One-click templates. Deploy open-source apps, like databases, analytics and dev tools, to your own server in one click.
- Managed databases. Postgres, MySQL and Redis with scheduled, restore-verified backups and point-in-time recovery.
- Push-to-deploy. Deploy from GitHub, GitLab or the CLI, with automatic HTTPS and zero-downtime releases.