LobeHub (Lobe Chat) with Docker: Self-Hosted AI Chat with Ollama (Linux, Windows, Mac)
Before you start
- 21 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
LobeHub (the project formerly called Lobe Chat) is a self-hosted chat website for AI models: you log in from any browser and talk to local models through Ollama or to cloud models with your own API keys, while chats, agents and files stay on your server.

Logo: the official LobeHub project (github.com/lobehub/lobehub)
It suits a family or small team that wants one private chat page for many models. Version 2 keeps everything in a PostgreSQL database, so your history follows you from laptop to phone. LobeHub is only the chat layer: Ollama or a cloud provider runs the model. The stack is bigger than most guides here (six containers).
| What | Value (official docs, read October 2026) |
|---|---|
| Current version | LobeHub 2.2.21, released 29 October 2026 (the repository moved from lobehub/lobe-chat to lobehub/lobehub) |
| Image to pin | lobehub/lobehub:2.2.21 (checked on Docker Hub) |
| Time needed | About 30 minutes, plus image downloads (our estimate, not measured) |
| Size and RAM | Image about 318 MB compressed (Docker Hub). Docs: 2 CPU cores, 4 GB RAM, 20 GB disk minimum; 4+ cores, 8+ GB RAM, 50+ GB recommended |
| Ports | 3210 (web app), 8787 (agent gateway, WebSocket), 9000 and 9001 (file storage and its console), 8788 (device gateway) |
| Licence | LobeHub Community License: Apache 2.0 plus extra conditions (not an OSI open-source licence) |
| Official docs | lobehub.com/docs/self-hosting and the repository |
At a glance:
- What it is: a chat app, a PostgreSQL database, a file store and an agent gateway in one Compose file.
- Models: local ones through Ollama, cloud ones with your own API keys.
- Old "client-only mode" is gone: version 2 supports only the database mode. Advice that mentions
NEXT_PUBLIC_SERVICE_MODE=clientor thelobe-chatimages is for version 1. - Change the defaults: the script makes new secrets but leaves the database password at a value published in the repository.
- Platforms: Linux and Mac run the official script. Windows needs WSL 2 (the docs say so).
- Privacy: chats and keys stay in your database. Cloud models see what you send them.
How it fits together#
Your browser talks to one app container on port 3210. The app keeps chats in PostgreSQL, files in RustFS (an S3-style file store) and runs agents through a gateway. Models live elsewhere: Ollama on the host, or a cloud provider.
Drawn for this guide from the official compose file and docs. Dashed boxes are optional.
Before you start#
You need a computer that stays on, Docker with Compose, and at least 20 GB of free disk (the docs' minimum).
Linux: Docker Engine and Docker Compose 2.24.4 or newer (our override file needs it), curl, openssl and bash. Check:
docker --version docker compose version openssl version
Windows: Docker Desktop with the WSL 2 backend and a distribution such as Ubuntu with WSL integration turned on. The docs say Windows users must run the script through WSL 2. Check from PowerShell:
wsl --status wsl -l -v docker --version docker compose version
Mac: Docker Desktop. bash, curl and openssl ship with macOS. Check in Terminal:
docker --version docker compose version openssl version
Checklist:
- [ ] Docker Compose 2.24.4 or newer (
docker compose version) - [ ] Ports 3210, 8787, 8788, 9000 and 9001 free (the docs name these)
- [ ] 4 GB RAM free for the stack, more if Ollama runs here too
- [ ] Ollama installed if you want local models (see our Ollama guide)
- [ ] For the HTTPS section only: a domain with three DNS records pointing at the server, and ports 80 and 443 free
Tested by DIY Lab Hub: not yet. The commands come from the official docs, compose file and setup.sh at release 2.2.21, read in October 2026. We did not run them.
Step 1: Create the project folder#
Every file lives in ~/docker_volumes/lobehub. The Compose file keeps PostgreSQL data in a data folder inside it.
Linux#
mkdir -p ~/docker_volumes/lobehub/backups cd ~/docker_volumes/lobehub
Windows (PowerShell)#
Open your WSL 2 shell from PowerShell and work inside Linux, not in your Windows profile.
wsl
Then, in the Linux shell that opens:
mkdir -p ~/docker_volumes/lobehub/backups cd ~/docker_volumes/lobehub
Mac (Terminal)#
Same commands as Linux:
mkdir -p ~/docker_volumes/lobehub/backups cd ~/docker_volumes/lobehub
Check it worked. pwd prints the lobehub folder and ls shows backups.
Tip: On Windows, keep the project in the Linux file system (
~in WSL), not under/mnt/c, where database files are slow and can hit permission trouble.
Step 2: Download the release files and create the secrets#
The official quick start runs a script from lobe.li that downloads files from the moving main branch. We take the same script and files from the 2.2.21 release instead, with the script's own --url option.
Linux#
cd ~/docker_volumes/lobehub curl -fsSL -o setup.sh https://raw.githubusercontent.com/lobehub/lobehub/v2.2.21/docker-compose/setup.sh bash setup.sh -l en --url https://raw.githubusercontent.com/lobehub/lobehub/v2.2.21
The script asks three questions. Answer like this:
| Question | Answer | Why |
|---|---|---|
| Deploy mode (0, 1, 2) | 2 (local, the default) | One computer. Domain mode is covered in the HTTPS section |
| Regenerate security secrets? | y | New AUTH_SECRET, KEY_VAULTS_SECRET, RustFS password, gateway token and key pair |
| Initialize the database? | n | So the database folder does not exist yet and we can set its password first |
Windows (PowerShell)#
Run the Linux commands in the WSL 2 shell. Keep Docker Desktop running: without Node.js the script makes its key pair with the LobeHub image.
Mac (Terminal)#
Same commands as Linux:
cd ~/docker_volumes/lobehub curl -fsSL -o setup.sh https://raw.githubusercontent.com/lobehub/lobehub/v2.2.21/docker-compose/setup.sh bash setup.sh -l en --url https://raw.githubusercontent.com/lobehub/lobehub/v2.2.21
Check it worked. The script prints a report with the RustFS user admin and a password. ls -a shows docker-compose.yml, .env, bucket.config.json and searxng-settings.yml.
Tip: Do not paste the report into a chat or ticket; it contains the RustFS password.
Step 3: Change the default password, pin the image, close the ports#
Four things in the shipped .env.example and compose file are unsafe or unstable: a fixed database password, an image with no tag, PostgreSQL and Redis published on every interface, and open registration (an empty AUTH_ALLOWED_EMAILS allows everyone). We fix all four.
Linux#
cd ~/docker_volumes/lobehub
# 1. new database password (the database has not been created yet)
NEWPW=$(openssl rand -hex 16)
sed "s#^POSTGRES_PASSWORD=.*#POSTGRES_PASSWORD=${NEWPW}#" .env > .env.new && mv .env.new .env
# 2. allow only your email to register, and point LobeHub at Ollama
printf 'AUTH_ALLOWED_EMAILS=<[email protected]>\nOLLAMA_PROXY_URL=http://host.docker.internal:11434\n' >> .env
chmod 600 .env
# 3. pin the image (three lines change)
sed 's#image: lobehub/lobehub$#image: lobehub/lobehub:2.2.21#' docker-compose.yml > docker-compose.yml.new && mv docker-compose.yml.new docker-compose.yml
grep -n "image: lobehub/lobehub" docker-compose.yml
Replace <[email protected]> with your email. Now create the override file. Compose merges docker-compose.override.yml into the main file automatically; !override and !reset need Compose 2.24.4 or newer (Docker's merge reference).
services:
lobe:
ports: !override
- "127.0.0.1:${LOBE_PORT}:3210"
extra_hosts:
- "host.docker.internal=host-gateway"
postgresql:
ports: !reset []
redis:
ports: !reset []
rustfs:
ports: !override
- "127.0.0.1:${RUSTFS_PORT}:9000"
- "127.0.0.1:${RUSTFS_ADMIN_PORT}:9001"
gateway:
ports: !override
- "127.0.0.1:${AGENT_GATEWAY_PORT:-8787}:8787"
- "127.0.0.1:${DEVICE_GATEWAY_PORT:-8788}:8788"
Save it as ~/docker_volumes/lobehub/docker-compose.override.yml. The extra_hosts line lets the container reach the host as host.docker.internal (Docker's host-gateway value).
Windows (PowerShell)#
Run the Linux block in the WSL 2 shell and save the override file there. http://localhost:3210 then works in your Windows browser.
Mac (Terminal)#
Same commands as Linux; the sed form (new file, then mv) also works with macOS sed.
Check it worked. grep -n "image: lobehub/lobehub" shows :2.2.21 on three lines. docker compose config > /dev/null && echo ok prints ok (Compose merges both files and finds no error).
Tip: Changing
POSTGRES_PASSWORDafter PostgreSQL has started does not change its real password. If you answeredyin Step 2,dataexists with the old one; it holds no chats yet, so remove it (the docs' FAQ usessudo rm -rf ./data) and redo Step 3.
Step 4: Start LobeHub and create your account#
Linux#
cd ~/docker_volumes/lobehub docker compose up -d docker compose ps docker logs -f lobehub
Press Ctrl+C to leave the log view. The first start downloads images and creates the tables, so allow a few minutes.
Windows (PowerShell)#
Run the same commands in the WSL 2 shell. Then open http://localhost:3210 in your Windows browser.
Mac (Terminal)#
Same commands as Linux. Then open http://localhost:3210.
Check it worked. The official docs list this as the expected end of the log (labelled "from the docs", not our output):
[Database] Start to migration... ✅ database migration pass. ▲ Next.js 16.x.x - Local: http://localhost:3210 ✓ Ready in 95ms
docker compose ps should list six running containers (lobehub, lobe-postgres, lobe-redis, lobe-rustfs, lobe-gateway, lobe-searxng). Open http://localhost:3210 and register with the email you allowed in Step 3.
Tip:
docker compose ps -aalso listslobe-rustfs-initas exited. Exit code 0 is normal: it creates the file bucket and its CORS rule once.
Step 5: Connect Ollama#
LobeHub's server calls Ollama. Ollama must accept connections from the container, and LobeHub must know the address: the OLLAMA_PROXY_URL line from Step 3 sets it. New to Ollama? Use our Ollama guide.
Linux#
The LobeHub docs make Ollama listen on all interfaces with a systemd override:
sudo systemctl edit ollama.service
Add these lines in the editor, save and exit:
[Service] Environment="OLLAMA_HOST=0.0.0.0"
Then reload and restart, and recreate the LobeHub container so it reads .env:
sudo systemctl daemon-reload sudo systemctl restart ollama cd ~/docker_volumes/lobehub && docker compose up -d
Windows (PowerShell)#
The docs say Ollama on Windows reads your user environment variables: quit Ollama from the tray, set the variable, start it again. This PowerShell line replaces the docs' control-panel steps (the command is ours):
[Environment]::SetEnvironmentVariable("OLLAMA_HOST", "0.0.0.0", "User")
Relaunch Ollama from the Start menu. Then, in the WSL 2 shell, run cd ~/docker_volumes/lobehub && docker compose up -d.
Mac (Terminal)#
For the Ollama app the docs use launchctl:
launchctl setenv OLLAMA_HOST "0.0.0.0"
Quit and restart the Ollama app, then run cd ~/docker_volumes/lobehub && docker compose up -d.
In LobeHub open App Settings, AI Providers, Ollama, check that the address is http://host.docker.internal:11434, enable the provider and press Check. Pull a model first if you have none (ollama pull <model-name>).
Check it worked. The Check button succeeds and the model list shows your Ollama models. A first reply in a new chat comes from the local model.
The docs also set OLLAMA_ORIGINS="*". That is CORS, which matters only when the browser itself calls Ollama (the Client Request Mode switch). Our reading, not tested: the server route here is server to server, so skip OLLAMA_ORIGINS unless you use that switch. OLLAMA_HOST=0.0.0.0 puts Ollama on your network with no login, so firewall port 11434 on a shared network. To reach Ollama from elsewhere, see Ollama over a private network.
Tip: Never type
localhost:11434as the Ollama address when LobeHub runs in Docker: inside the container,localhostis the container itself. Version 1 reports #5694 and #5984 describe the server still calling127.0.0.1.
Put it behind HTTPS (with or without Traefik)#
LobeHub works on http://localhost:3210 on one computer. A server with a domain needs HTTPS, and LobeHub needs three public names, not one. Local-only users can skip this section.
| Name (example) | Goes to | Why |
|---|---|---|
lobe.<your-domain> | LobeHub, port 3210 | The app |
s3.<your-domain> | RustFS, port 9000 | Your browser uploads files straight to it |
gateway.<your-domain> | Gateway, port 8787 | Agent runs stream over WebSocket |
First change three lines in .env (the docs' domain mode sets exactly these): APP_URL=https://lobe.<your-domain>, S3_ENDPOINT=https://s3.<your-domain> and AGENT_GATEWAY_URL=https://gateway.<your-domain>. Leave INTERNAL_APP_URL=http://localhost:3210; the docs require it for Docker. The docs also say one-click deployment does not support self-signed certificates by default, so a home-only name with Caddy's tls internal is our own suggestion, untested.
With Traefik#
On a server that already runs Traefik v3 with the Docker provider, add labels and join the proxy network.
This assumes an external network proxy and an entrypoint https (the docs name it websecure; use yours). Create the network once if missing:
docker network create proxy
Replace docker-compose.override.yml with this file. It keeps the Step 3 changes and adds the labels. The merge is ours and was not run:
services:
lobe:
ports: !reset []
extra_hosts:
- "host.docker.internal=host-gateway"
networks:
- lobe-network
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.lobe.rule=Host(`lobe.<your-domain>`)"
- "traefik.http.routers.lobe.entrypoints=https"
- "traefik.http.routers.lobe.tls=true"
- "traefik.http.services.lobe.loadbalancer.server.port=3210"
rustfs:
ports: !override
- "127.0.0.1:${RUSTFS_ADMIN_PORT}:9001"
networks:
- lobe-network
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.lobe-s3.rule=Host(`s3.<your-domain>`)"
- "traefik.http.routers.lobe-s3.entrypoints=https"
- "traefik.http.routers.lobe-s3.tls=true"
- "traefik.http.services.lobe-s3.loadbalancer.server.port=9000"
gateway:
ports: !override
- "127.0.0.1:${DEVICE_GATEWAY_PORT:-8788}:8788"
networks:
- lobe-network
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.lobe-gw.rule=Host(`gateway.<your-domain>`)"
- "traefik.http.routers.lobe-gw.entrypoints=https"
- "traefik.http.routers.lobe-gw.tls=true"
- "traefik.http.services.lobe-gw.loadbalancer.server.port=8787"
postgresql:
ports: !reset []
redis:
ports: !reset []
networks:
proxy:
external: true
Run docker compose up -d in ~/docker_volumes/lobehub. The gateway needs WebSocket upgrades (docs); we believe Traefik forwards them without extra labels but did not test it. The docs' own Traefik example uses the letsencrypt resolver; use whichever your Traefik has.
Check it worked. curl -I https://lobe.<your-domain>/ returns an HTTP status line over HTTPS and the page opens with a valid certificate.
Without Traefik: Caddy#
Choose this if you have no Traefik. Caddy gets and renews certificates itself and handles WebSocket upgrades without extra settings.
| Case | What Caddy does | What you need |
|---|---|---|
| Public domain | Gets Let's Encrypt certificates automatically | DNS records for all three names, ports 80 and 443 open |
| Home only | tls internal: Caddy's own local certificate | Install Caddy's root certificate on each device |
Use the override file above without the labels: blocks so the three services join proxy. Then create the Caddy folder:
mkdir -p ~/docker_volumes/caddy/{data,config}
cd ~/docker_volumes/caddy
docker network create proxy
Save as ~/docker_volumes/caddy/docker-compose.yml (caddy:2.11.7 is the latest Caddy release, read October 2026):
services:
caddy:
image: caddy:2.11.7
container_name: caddy
restart: unless-stopped
ports:
- "80:80/tcp"
- "443:443/tcp"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
networks:
- proxy
networks:
proxy:
external: true
Save as ~/docker_volumes/caddy/Caddyfile, using the container names from the official compose file:
lobe.example.com {
reverse_proxy lobehub:3210
}
s3.example.com {
reverse_proxy lobe-rustfs:9000
}
gateway.example.com {
reverse_proxy lobe-gateway:8787
}
Home only: add tls internal inside each block and use your own names:
lobe.home.arpa {
tls internal
reverse_proxy lobehub:3210
}
Start both stacks:
cd ~/docker_volumes/caddy && docker compose up -d cd ~/docker_volumes/lobehub && docker compose up -d
With tls internal, Caddy's docs say you install its root certificate on each device yourself:
docker exec caddy find /data -name root.crt docker cp caddy:<path-from-find> ./caddy-root.crt
Add caddy-root.crt as a trusted root. These per-system steps are not from the Caddy docs: Windows "Trusted Root Certification Authorities", macOS Keychain Access with "Always Trust", Linux your distribution's CA store. Windows and Mac are only clients here; the Docker commands run on the server.
Check it worked. curl -I https://lobe.example.com/ returns an HTTP status line over HTTPS. A home name shows a padlock only after the root is trusted.
Tip: A certificate error usually means the Caddyfile name differs from the DNS record, or port 80 is blocked (Let's Encrypt needs it). If the page loads but uploads fail, check
s3.<your-domain>first.
Security and testing#
A chat page with your API keys behind it is worth protecting.
| Control | How |
|---|---|
| Registration | AUTH_ALLOWED_EMAILS lists who may register (emails or whole domains). AUTH_DISABLE_EMAIL_PASSWORD=1 forces single sign-on |
| Secrets | The script made new AUTH_SECRET, KEY_VAULTS_SECRET, JWKS_KEY, gateway token and RustFS password. Step 3 set the database password |
| Old example key | The docs warn an .env holding the old example JWKS_KEY (kid 6823046760c5d460) lets anyone forge tokens. grep -c 6823046760c5d460 .env must print 0 |
| Ports | Step 3 keeps every port on 127.0.0.1 and closes PostgreSQL and Redis |
.env | chmod 600 .env; never commit it; its backups are secrets too |
| Ollama | OLLAMA_HOST=0.0.0.0 has no login. Firewall port 11434 on a shared network |
Quick tests after each change:
cd ~/docker_volumes/lobehub docker compose ps docker compose logs --tail=100 lobe docker compose exec postgresql pg_isready -U postgres curl -I http://localhost:3210/
Windows runs these in the WSL 2 shell, Mac in Terminal. For HTTPS, run curl -I https://lobe.<your-domain>/ from any system (curl.exe ships with Windows 10 and 11).
Database mode, not client-only mode#
Older Lobe Chat guides describe a "client-only" mode: chats in the browser (a PGlite database), no server database. The official version 2 breaking-changes page says: "LobeHub 2.0 only supports Server DB mode. Client DB (PGlite) is no longer supported."
Version 1 (lobe-chat) | Version 2 (lobehub) | |
|---|---|---|
| Chats live in | Browser (client mode) or server database | Server database only |
| Image | lobehub/lobe-chat, lobehub/lobe-chat-database | lobehub/lobehub |
| Login | Access code, NextAuth, Clerk | Better Auth (email and password, or single sign-on) |
If you want a quick single-user chat page with no database, version 2 is the wrong tool. Open WebUI, LibreChat and AnythingLLM are other self-hosted chat pages we cover. Coming from version 1? The project has migration pages for the login system; back up first.
Common mistakes#
These come from the official docs, the compose file at the release tag and the project's GitHub issues.
| Mistake | Why it happens | Do this instead |
|---|---|---|
Keeping the default POSTGRES_PASSWORD | .env.example ships a fixed value and setup.sh regenerates the other secrets, not this one | Set a random one before the first start (Step 3) |
| Leaving PostgreSQL and Redis published on all interfaces | The official compose file maps 5432 and 6379 and calls them optional | Remove them with the override file |
Using image: lobehub/lobehub with no tag | The official file has none, so latest moves; issue #17647 (open) shows latest lagging | Pin 2.2.21; read the release notes before changing it |
rustfs-init exits with unknown field `ID` | Older bucket.config.json files wrote "ID" instead of "Id" (#17002, #18139, closed) | Use the files from the release tag; they say "Id" |
| File uploads fail with a CORS or 403 error | S3_ENDPOINT must be reachable from the browser (docs); 2.2.17 also had an upload bug with RustFS (#19661, fixed in 2.2.18) | Use a browser-reachable S3_ENDPOINT and a current 2.2.x |
JWKS_KEY environment variable is not set | Version 2 requires it (#11195, #11304) | Let setup.sh generate it |
Typing localhost:11434 for Ollama inside Docker | localhost is the container itself | Use http://host.docker.internal:11434 plus the extra_hosts line |
Running setup.sh again | It refuses when data exists, and deleting data deletes your chats | Edit .env by hand; back up before any clean start |
| Proxying only the app | The docs list three public names; the gateway needs WebSocket upgrades | Proxy all three (HTTPS section) |
AI assistants: NEXT_PUBLIC_SERVICE_MODE=client, ACCESS_CODE, NEXTAUTH_URL or the lobehub/lobe-chat image | These are version 1 settings; the version 2 docs list them as removed | Use lobehub/lobehub, AUTH_SECRET and JWKS_KEY as in this guide |
AI assistants: a one-line docker run for the whole app | The docs' single-container example still needs an external PostgreSQL and S3 storage | Use the Compose route |
Tip: After every change, run
docker compose logs --tail=100 lobe. Most start-up errors (database, secrets, S3) print there with the exact text.
Tip: LobeHub releases weekly (616 merged pull requests between 2.2.20 and 2.2.21). Read the release notes and back up before you change the pinned tag.
Tip: Make the DNS records for all three public names before you start Caddy or Traefik. A missing
s3orgatewayrecord looks like a working app with broken uploads and agents.
Troubleshooting#
| Problem | Solution |
|---|---|
| Page does not open on port 3210 | docker compose ps, then docker compose logs --tail=100 lobe. The app waits for PostgreSQL, Redis and RustFS to be healthy; the first start can take minutes |
| Port already in use | Change LOBE_PORT, RUSTFS_PORT, RUSTFS_ADMIN_PORT or AGENT_GATEWAY_PORT in .env, or stop the other program |
lobe-gateway keeps restarting after an upgrade | The new compose file needs the gateway variables in .env. Follow the docs' "Upgrading an Existing Deployment", then docker compose up -d --force-recreate |
| Cannot log in, or you land back on the page not logged in | APP_URL must match the address in your browser (behind a proxy, the HTTPS name). Report #11740 describes the symptom; we found no confirmed cause |
| Upload fails with a network error | docker compose logs rustfs rustfs-init, then docker compose up -d --force-recreate rustfs-init (the docs) |
| Ollama Check fails | From the host, curl http://localhost:11434/api/tags should list models. Restart Ollama after setting OLLAMA_HOST, and confirm OLLAMA_PROXY_URL is in .env |
| Database connection error | docker compose exec postgresql pg_isready -U postgres, then docker compose logs postgresql |
| Cloud answers stop after about 65 seconds | Open report #18378. The docs list ANTHROPIC_CLIENT_TIMEOUT (milliseconds, default 295000); we did not test whether it helps |
service "rustfs-init" didn't complete successfully: exit 1#
Reports #17002 and #18139 show Io error: unknown field `ID` . Check the mounted file and the log:
cd ~/docker_volumes/lobehub grep -n '"Id"\|"ID"' bucket.config.json docker compose logs rustfs-init
The 2.2.21 file has "Id". In #18139 the file was already right and the error went away only after docker compose down -v and up -d. down -v deletes the named volumes (uploads, Redis data) but not data; use it only on a fresh install.
JWKS_KEY environment variable is not set#
Check that grep -c '^JWKS_KEY=' .env prints 1 and the value is not YOUR_JWKS_KEY. Make a new pair with the command in the docs' "Necessary Configuration" section, then docker compose up -d --force-recreate.
Known bugs (open, October 2026)#
- #17647: Docker Hub
latestlagged days behind new model cards. Pin a version. - #19038: an image tagged 2.2.15 reported version 2.2.14, and 2.2.18 reported 2.2.17. Trust the tag you pulled, not the number shown.
- #18378: requests to an Anthropic-compatible provider fail after about 65 seconds.
- #20736: self-hosted community agent pages fail with
invalid_tokenon 2.2.19. We did not check 2.2.21.
Updates and backups#
Update. Read the release notes, back up, change the tag in docker-compose.yml (three lines), then:
cd ~/docker_volumes/lobehub docker compose pull docker compose up -d docker compose logs --tail=100 lobe
The image runs the database migration itself before it starts (the docs). So back up first: a dump is your way back if a migration fails.
Back up. The database holds your chats, agents and settings. .env holds the secrets that go with it. Save this as ~/docker_volumes/lobehub/backup.sh:
#!/usr/bin/env bash set -euo pipefail cd ~/docker_volumes/lobehub DB=$(grep '^LOBE_DB_NAME=' .env | cut -d= -f2) STAMP=$(date +%F) mkdir -p backups docker compose exec -T postgresql pg_dump -U postgres "$DB" > "backups/lobehub-db-$STAMP.sql" cp .env "backups/lobehub-env-$STAMP" chmod 600 backups/lobehub-*
Uploaded files live in the Docker volume rustfs-data, not in the project folder. The docs give this two-step copy (we did not run it, and we do not know whether the RustFS image contains tar):
docker compose exec rustfs tar czf /tmp/backup.tar.gz /data docker cp lobe-rustfs:/tmp/backup.tar.gz ./backups/rustfs-backup.tar.gz
Schedule. Linux and Mac, 03:00 every night (crontab -e):
0 3 * * * bash ~/docker_volumes/lobehub/backup.sh
Windows, with Task Scheduler running the script inside WSL 2 (the command is ours; replace Ubuntu with your distribution name):
$action = New-ScheduledTaskAction -Execute "wsl.exe" -Argument "-d Ubuntu -- bash -lc '~/docker_volumes/lobehub/backup.sh'" $trigger = New-ScheduledTaskTrigger -Daily -At 3:00AM Register-ScheduledTask -TaskName "LobeHub backup" -Action $action -Trigger $trigger
Restore test. Restore into a throw-away database, never over the live one. The restore command is from the docs; the scratch database name is ours:
cd ~/docker_volumes/lobehub docker compose exec -T postgresql psql -U postgres -c "CREATE DATABASE restore_test;" docker compose exec -T postgresql psql -U postgres restore_test < backups/lobehub-db-<date>.sql docker compose exec -T postgresql psql -U postgres restore_test -c "\dt" | head docker compose exec -T postgresql psql -U postgres -c "DROP DATABASE restore_test;"
If \dt lists tables, the dump is usable. Copy the backups folder to another machine.
Performance and resources#
The docs give sizing, not measurements: minimum 2 CPU cores, 4 GB RAM, 20 GB disk; recommended 4 or more cores, 8 GB or more RAM, 50 GB or more disk. We measured nothing.
- Live use:
docker statsshows CPU and memory per container;docker system dfshows disk. - Models: LobeHub does not run them; Ollama does, and needs its own memory.
- Search: PostgreSQL's
pg_searchis the default. The optional Elasticsearch service needs at least 2 GB RAM on its own and stays off unless you enable its profile. - Knowledge base (RAG): search over your own documents uses database extensions in the ParadeDB image, and uploads need working S3 access from your browser.
FAQ#
Is LobeHub the same as Lobe Chat? Yes. lobehub/lobe-chat now redirects to lobehub/lobehub, and version 2 uses the new name. The licence text and old guides still say LobeChat.
Is it free to use? Yes, under the LobeHub Community License: Apache 2.0 plus extra conditions. Commercial use is allowed without changing the source; a commercial licence is needed to develop and distribute a derivative work. Read the LICENSE before building a product on it.
Can I run it without Ollama? Yes. Add a cloud provider key under App Settings, AI Providers (the docs name OpenAI, Anthropic and Google, among others).
Can I run it on a Raspberry Pi? Docker Hub has arm64 and amd64 images and the docs give 4 GB RAM as the minimum. We did not test it.
Does it send my data to the project? The docs describe optional analytics, off unless you set ENABLE_VERCEL_ANALYTICS=1, and say they do not support Docker. We did not audit traffic. Cloud models receive what you send them.
Can Windows or Mac be the server? Mac runs the official script. Windows needs WSL 2. For an always-on server, Linux is simpler.
Sources#
- LobeHub release v2.2.21, README, LICENSE, docker-compose.yml, .env.example and setup.sh - read October 2026
- Self-hosting docs at v2.2.21 (start, Docker Compose, Docker, Ollama example, environment variables, version 2 breaking changes) and the rendered LobeHub self-hosting docs - read October 2026
- Using Ollama in LobeHub - read October 2026
- LobeHub image on Docker Hub (tag 2.2.21 checked) - October 2026
- Docker: merge Compose files and
docker container run(host-gateway) - read October 2026 - Caddy release v2.11.7, automatic HTTPS and running Caddy - read October 2026
- GitHub issues #5694, #5984, #11195, #11740, #15584, #17002, #17647, #18139, #18378, #19038, #19661, #20736 - read October 2026
Checked against the official docs on 2026-10-31.