If you have followed along with the previous articles in this series, you now have Ollama running as a service and probably one of the simpler frontends on top of it. Open WebUI gives you a clean ChatGPT-style chat history. AnythingLLM gives you workspace-isolated document RAG. Both are excellent, but they each solve a single, well-defined problem.
LibreChat solves a different set of problems. It is an open-source, self-hosted chat interface designed for users who need to interact with multiple AI providers in a single place without switching tools. On top of multi-provider support, LibreChat adds conversation branching (fork any message and explore two paths simultaneously), a visual artifact renderer for HTML and code, a plugin and agent system, and multi-user support with proper authentication.
This tutorial walks you through installing LibreChat on Ubuntu using Docker Compose, connecting it to Ollama, and getting familiar with the features that make it genuinely different from the frontends you may already have running.
What Makes LibreChat Different
Before touching any commands, it is worth understanding why you might choose LibreChat over the simpler options.
Multi-provider in one interface. Open WebUI and AnythingLLM are designed around a single backend, usually Ollama. LibreChat is built from the ground up to connect to many providers simultaneously. You can have Ollama (local), OpenAI GPT-4o (cloud), and Anthropic Claude (cloud) available in the same session and switch between them from a dropdown. This matters when you want to compare outputs, fall back to a cloud model for a hard task, or route different agents to different backends.
Conversation branching. In most chat UIs, a conversation is a linear thread. LibreChat lets you branch from any message. Click the fork icon on any assistant response, edit your previous prompt, and a new branch appears. The original branch is preserved. This is genuinely useful for prompt engineering, you can try five variations of a prompt and keep the best thread without losing the others.
Artifacts. When a model produces HTML, a React component, or structured data, LibreChat can render it visually in a side panel. Code outputs run in a sandboxed iframe. This is the same behavior as Claude’s artifacts feature, but self-hosted and working with any model.
Agents and tools. LibreChat ships a framework for creating AI agents that have access to external tools. Web search via Tavily, code execution, file operations, and more. Unlike AnythingLLM’s agents (which are mainly query-plus-web-search), LibreChat’s agent framework is closer to what OpenAI’s Assistant API or Claude’s tool use provides.
Prerequisites
- Ubuntu 20.04, 22.04, or 24.04
- Ollama installed and running
- At least one model pulled (for example
ollama pull llama3.2:3b) - Docker and Docker Compose installed
- At least 2 GB of free RAM beyond what your models use
- At least 10 GB of free disk space
- A user with
sudoprivileges
Confirm Ollama is reachable before you start:
curl http://localhost:11434/api/tags
A JSON response with your model list means Ollama is ready. A connection error means Ollama is not running, start it with sudo systemctl start ollama.
Step 1: Install Docker and Docker Compose
Skip this step if Docker is already installed.
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
Docker Compose v2 is included in modern Docker Engine installations. Verify both:
docker --version
docker compose version
You should see version numbers for both commands. If docker compose is missing, install the plugin explicitly:
sudo apt install docker-compose-plugin -y
Step 2: Clone the LibreChat Repository
LibreChat is distributed as a Docker Compose application and relies on configuration files that live alongside the compose file. The easiest way to get everything in the right place is to clone the repository:
git clone https://github.com/danny-avila/LibreChat.git ~/librechat
cd ~/librechat
This gives you the full project layout including the default configuration files and the compose file.
Step 3: Create the Environment File
LibreChat uses a .env file for all configuration. A template is provided:
cp .env.example .env
Open the file:
nano .env
At minimum, you need to set a few values to get a working installation:
Set a secure JWT secret. LibreChat uses JWT tokens for session management. Set a long, random secret:
# Generate a secure random string
openssl rand -hex 32
Copy the output, then in .env find and set:
JWT_SECRET=paste-your-generated-secret-here
JWT_REFRESH_SECRET=paste-a-different-generated-secret-here
Run openssl rand -hex 32 a second time for the refresh secret, use a different value.
Set a domain for cookies. If you are running locally, the default is fine. For a server accessible from other machines, set:
DOMAIN_CLIENT=http://your-server-ip:3080
DOMAIN_SERVER=http://your-server-ip:3080
Disable registration if you want a private instance. By default, anyone who reaches the URL can create an account. To require an invite or disable sign-up entirely:
ALLOW_REGISTRATION=false
Save and close the file.
Step 4: Configure Ollama as a Provider
LibreChat uses a YAML configuration file to define AI providers and their endpoints. Copy the example:
cp librechat.example.yaml librechat.yaml
Open it:
nano librechat.yaml
Find the endpoints section. Add an Ollama entry. The structure looks like this:
endpoints:
custom:
- name: "Ollama"
apiKey: "ollama"
baseURL: "http://host.docker.internal:11434/v1/"
models:
default: ["llama3.2:3b"]
fetch: true
titleConvo: true
titleModel: "llama3.2:3b"
summarize: false
summaryModel: "llama3.2:3b"
forcePrompt: false
modelDisplayLabel: "Ollama"
A few things to note here:
baseURLpoints tohost.docker.internal. This is the hostname Docker provides for containers to reach services running on the host machine. Since Ollama runs on the host, not inside Docker, this is how LibreChat inside the container finds it.apiKey: "ollama". Ollama does not require an API key, but the field must not be empty. Any non-empty string works.fetch: true. Tells LibreChat to fetch the model list from the Ollama API at startup rather than only using the staticdefaultlist. This means any models you pull withollama pullwill automatically appear in the dropdown.
Save the file.
Step 5: Start LibreChat
With the configuration in place, start all services:
docker compose up -d
This command starts three containers: the LibreChat API backend, the React frontend, and a MongoDB instance that stores conversations and user accounts. The first run downloads several images which takes a few minutes.
Watch the logs to confirm everything started cleanly:
docker compose logs -f api
Look for a line like Server is listening on port 3080. That confirms the backend is ready. Press Ctrl+C to stop following the logs.
Check that all three containers are up:
docker compose ps
You should see librechat-api, librechat-frontend (or similar names), and librechat-mongodb with status Up.
Step 6: Create the First Account
Open a browser and navigate to http://localhost:3080 (or replace localhost with your server’s IP).
You will see a login page. Click Create an account and register with an email address and password. The first account created automatically becomes an admin account.
After logging in, you land on the main chat interface.
Step 7: Start a Conversation with Ollama
In the top left of the interface, there is a provider selector. Click it and choose Ollama from the list (this is the entry you configured in librechat.yaml).
Next to the provider selector is a model dropdown. Click it and select the model you want to use, for example llama3.2:3b. If fetch: true is working, all your locally pulled models appear here automatically.
Type a message and send it. The response streams back in real time.
Step 8: Explore Conversation Branching
Conversation branching is the feature most users discover last but end up relying on constantly.
After the model responds to your first message, hover over the response. You will see a small set of icons appear. Click the fork or edit icon to create a branch. Edit your original prompt to try a different angle, then send. A new response appears while the original branch remains intact.
You can switch between branches using the navigation arrows at the message where the fork happened. This is how you compare prompt variations side by side without losing your work.
Step 9: Expose LibreChat Behind Nginx (Optional)
By default, LibreChat runs on port 3080 over plain HTTP. If you want HTTPS or access from outside your local network, put it behind Nginx.
Install Nginx if you do not have it:
sudo apt install nginx -y
Create a server block:
sudo nano /etc/nginx/sites-available/librechat
Paste:
server {
listen 80;
server_name chat.example.com;
client_max_body_size 20M;
location / {
proxy_pass http://127.0.0.1:3080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
}
}
The Upgrade and Connection headers are required for WebSocket streaming. Without them, responses only appear after they are fully generated rather than streaming word-by-word.
Enable the site and reload Nginx:
sudo ln -s /etc/nginx/sites-available/librechat /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
For TLS, get a Let’s Encrypt certificate, the process is covered in Secure Nginx with Let’s Encrypt SSL Using Certbot on Ubuntu. After getting the certificate, update your .env to set DOMAIN_CLIENT and DOMAIN_SERVER to the HTTPS URL.
Managing and Updating LibreChat
Stop and start the services
docker compose stop
docker compose start
To stop and remove the containers (data in the MongoDB volume persists):
docker compose down
Update to the latest version
LibreChat releases updates frequently. To update:
git pull
docker compose pull
docker compose up -d
The git pull updates the compose file and configuration templates. docker compose pull downloads the latest image versions. Your MongoDB data and your .env / librechat.yaml files are not overwritten by either command.
Back up the MongoDB data
All conversations, user accounts, and settings are stored in a Docker-managed MongoDB volume. Back it up by running a mongodump inside the container:
docker compose exec mongodb mongodump \
--out /dump \
--db LibreChat
docker cp $(docker compose ps -q mongodb):/dump ./librechat-backup-$(date +%F)
This copies the dump out of the container to your current directory.
Common Mistakes and Troubleshooting
The Ollama provider shows no models in the dropdown
The most common cause is that the baseURL in librechat.yaml uses localhost instead of host.docker.internal. Inside a Docker container, localhost refers to the container itself, not the host machine where Ollama is running. Change the URL to http://host.docker.internal:11434/v1/ and restart:
docker compose restart api
Also verify the container can reach the host:
docker compose exec api curl http://host.docker.internal:11434/api/tags
If you get a connection error from this command, Ollama is binding to 127.0.0.1 only. Override it:
sudo systemctl edit ollama
Add:
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart ollama
Registration page appears even after setting ALLOW_REGISTRATION=false
Environment variable changes in .env require a container restart to take effect:
docker compose down
docker compose up -d
Streaming does not work, the full response appears at once
Check the Nginx proxy headers. The Upgrade and Connection "upgrade" headers must be present. If you forgot them, the browser falls back to polling instead of a WebSocket connection and the response appears all at once when complete.
The container starts but immediately exits
Check the logs:
docker compose logs api --tail 50
A common cause is a malformed librechat.yaml. YAML is sensitive to indentation, ensure you have not mixed tabs and spaces. The endpoints.custom section must be a list (prefixed with -).
JWT-related errors on login
The JWT_SECRET and JWT_REFRESH_SECRET values must be set in .env before the first startup. If you started with empty values, existing sessions may have invalid signatures. Stop the services, set valid secrets in .env, then start again. Existing user accounts in MongoDB are preserved; only active sessions are invalidated.
Best Practices
Do not expose the MongoDB port externally. The compose file does not publish MongoDB’s port 27017 by default, and it should stay that way. MongoDB has no authentication configured out of the box in the LibreChat compose setup, it relies on Docker networking isolation. If you ever open port 27017 to the host network, the database is accessible without credentials.
Use a dedicated admin account for admin tasks. Create a second account for everyday use and keep the admin account separate. LibreChat’s admin panel lives at /admin and gives access to all user data and system configuration. You do not want an admin token sitting in an active browser session during normal use.
Pin the Ollama model for production conversations. If you add a model and later remove it with ollama rm, existing conversations that reference it will fail to regenerate responses. Either keep all models you use in conversations installed, or explicitly archive those conversations before removing a model.
Keep librechat.yaml and .env in version control, in a private repository. These files contain your configuration and secrets. Having them versioned means you can recover from a server failure without reconfiguring from scratch. Never commit them to a public repository.
Use HTTPS in production. LibreChat transmits conversation content and credentials over HTTP by default. Even on a private network, TLS is worth the five-minute setup with Certbot. Browsers also require HTTPS for certain browser features to work correctly.
Conclusion
You now have LibreChat running on Ubuntu, backed by your local Ollama models, with conversation branching, a configurable multi-provider setup, and an Nginx reverse proxy ready for HTTPS.
The stack you have built is:
- Ollama running as a systemd daemon, serving inference requests on
localhost:11434 - LibreChat providing a full-featured chat interface with multi-provider support, branching, and agents
- Nginx in front for clean URL access and WebSocket-compatible proxying
From here, the natural next steps are:
- Add a cloud provider fallback. Configure an OpenAI or Anthropic key in
librechat.yamlso you can fall back to a cloud model when your local hardware cannot handle a task. Both can coexist with Ollama in the same interface. - Create a custom agent. Use LibreChat’s agent configuration to define an assistant with access to web search or a code interpreter. Agents can chain tool calls in a way that single-turn chat cannot.
- Explore the RAG upload feature. LibreChat supports per-conversation file uploads with vector search. Upload a PDF and ask questions about it, the model retrieves relevant passages before generating each answer.