DockerSelf-HostingAI

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.

LobeHub official logo

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).

WhatValue (official docs, read October 2026)
Current versionLobeHub 2.2.21, released 29 October 2026 (the repository moved from lobehub/lobe-chat to lobehub/lobehub)
Image to pinlobehub/lobehub:2.2.21 (checked on Docker Hub)
Time neededAbout 30 minutes, plus image downloads (our estimate, not measured)
Size and RAMImage 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
Ports3210 (web app), 8787 (agent gateway, WebSocket), 9000 and 9001 (file storage and its console), 8788 (device gateway)
LicenceLobeHub Community License: Apache 2.0 plus extra conditions (not an OSI open-source licence)
Official docslobehub.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=client or the lobe-chat images 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.

Diagram: your browser reaches the LobeHub container on port 3210, optionally through Caddy or Traefik for HTTPS; LobeHub reads and writes chats in PostgreSQL, stores uploaded files in RustFS on port 9000, runs agents through the gateway on port 8787, and calls Ollama on the host through host.docker.internal or cloud providers with an API key

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:

Run in terminalbash
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:

Run in terminalpowershell
wsl --status
wsl -l -v
docker --version
docker compose version

Mac: Docker Desktop. bash, curl and openssl ship with macOS. Check in Terminal:

Run in terminalbash
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#

Run in terminalbash
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.

Run in terminalpowershell
wsl

Then, in the Linux shell that opens:

Run in terminalbash
mkdir -p ~/docker_volumes/lobehub/backups
cd ~/docker_volumes/lobehub

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
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#

Run in terminalbash
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:

QuestionAnswerWhy
Deploy mode (0, 1, 2)2 (local, the default)One computer. Domain mode is covered in the HTTPS section
Regenerate security secrets?yNew AUTH_SECRET, KEY_VAULTS_SECRET, RustFS password, gateway token and key pair
Initialize the database?nSo 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:

Run in terminalbash
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#

Run in terminalbash
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).

File contentyaml
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_PASSWORD after PostgreSQL has started does not change its real password. If you answered y in Step 2, data exists with the old one; it holds no chats yet, so remove it (the docs' FAQ uses sudo rm -rf ./data) and redo Step 3.

Step 4: Start LobeHub and create your account#

Linux#

Run in terminalbash
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):

File contenttext
[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 -a also lists lobe-rustfs-init as 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:

Run in terminalbash
sudo systemctl edit ollama.service

Add these lines in the editor, save and exit:

File contenttext
[Service]
Environment="OLLAMA_HOST=0.0.0.0"

Then reload and restart, and recreate the LobeHub container so it reads .env:

Run in terminalbash
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):

File contentpowershell
[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:

Run in terminalbash
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:11434 as the Ollama address when LobeHub runs in Docker: inside the container, localhost is the container itself. Version 1 reports #5694 and #5984 describe the server still calling 127.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 toWhy
lobe.<your-domain>LobeHub, port 3210The app
s3.<your-domain>RustFS, port 9000Your browser uploads files straight to it
gateway.<your-domain>Gateway, port 8787Agent 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:

Run in terminalbash
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:

File contentyaml
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.

CaseWhat Caddy doesWhat you need
Public domainGets Let's Encrypt certificates automaticallyDNS records for all three names, ports 80 and 443 open
Home onlytls internal: Caddy's own local certificateInstall 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:

Run in terminalbash
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):

File contentyaml
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:

File contenttext
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:

File contenttext
lobe.home.arpa {
    tls internal
    reverse_proxy lobehub:3210
}

Start both stacks:

Run in terminalbash
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:

Run in terminalbash
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.

ControlHow
RegistrationAUTH_ALLOWED_EMAILS lists who may register (emails or whole domains). AUTH_DISABLE_EMAIL_PASSWORD=1 forces single sign-on
SecretsThe script made new AUTH_SECRET, KEY_VAULTS_SECRET, JWKS_KEY, gateway token and RustFS password. Step 3 set the database password
Old example keyThe docs warn an .env holding the old example JWKS_KEY (kid 6823046760c5d460) lets anyone forge tokens. grep -c 6823046760c5d460 .env must print 0
PortsStep 3 keeps every port on 127.0.0.1 and closes PostgreSQL and Redis
.envchmod 600 .env; never commit it; its backups are secrets too
OllamaOLLAMA_HOST=0.0.0.0 has no login. Firewall port 11434 on a shared network

Quick tests after each change:

Run in terminalbash
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 inBrowser (client mode) or server databaseServer database only
Imagelobehub/lobe-chat, lobehub/lobe-chat-databaselobehub/lobehub
LoginAccess code, NextAuth, ClerkBetter 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.

MistakeWhy it happensDo this instead
Keeping the default POSTGRES_PASSWORD.env.example ships a fixed value and setup.sh regenerates the other secrets, not this oneSet a random one before the first start (Step 3)
Leaving PostgreSQL and Redis published on all interfacesThe official compose file maps 5432 and 6379 and calls them optionalRemove them with the override file
Using image: lobehub/lobehub with no tagThe official file has none, so latest moves; issue #17647 (open) shows latest laggingPin 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 errorS3_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 setVersion 2 requires it (#11195, #11304)Let setup.sh generate it
Typing localhost:11434 for Ollama inside Dockerlocalhost is the container itselfUse http://host.docker.internal:11434 plus the extra_hosts line
Running setup.sh againIt refuses when data exists, and deleting data deletes your chatsEdit .env by hand; back up before any clean start
Proxying only the appThe docs list three public names; the gateway needs WebSocket upgradesProxy all three (HTTPS section)
AI assistants: NEXT_PUBLIC_SERVICE_MODE=client, ACCESS_CODE, NEXTAUTH_URL or the lobehub/lobe-chat imageThese are version 1 settings; the version 2 docs list them as removedUse lobehub/lobehub, AUTH_SECRET and JWKS_KEY as in this guide
AI assistants: a one-line docker run for the whole appThe docs' single-container example still needs an external PostgreSQL and S3 storageUse 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 s3 or gateway record looks like a working app with broken uploads and agents.

Troubleshooting#

ProblemSolution
Page does not open on port 3210docker 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 useChange LOBE_PORT, RUSTFS_PORT, RUSTFS_ADMIN_PORT or AGENT_GATEWAY_PORT in .env, or stop the other program
lobe-gateway keeps restarting after an upgradeThe 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 inAPP_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 errordocker compose logs rustfs rustfs-init, then docker compose up -d --force-recreate rustfs-init (the docs)
Ollama Check failsFrom 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 errordocker compose exec postgresql pg_isready -U postgres, then docker compose logs postgresql
Cloud answers stop after about 65 secondsOpen 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:

Run in terminalbash
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 latest lagged 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_token on 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:

Run in terminalbash
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:

File contentbash
#!/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):

Run in terminalbash
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):

File contenttext
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):

Codepowershell
$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:

Run in terminalbash
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 stats shows CPU and memory per container; docker system df shows disk.
  • Models: LobeHub does not run them; Ollama does, and needs its own memory.
  • Search: PostgreSQL's pg_search is 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#

Checked against the official docs on 2026-10-31.