Deploy · Intermediate

How to self-host a ChatGPT alternative

  • Time: About 1 to 2 hours for a working pilot, plus time for single sign-on and a short policy for users.
  • Cost: Free software. You pay for the server, power and the time to maintain it. Hosted model APIs, if you connect any, are billed by their providers.
  • Level: Intermediate
On this page
  1. Short answer
  2. Before you start
  3. The Open WebUI licence: read it if you will rebrand
  4. 1. Decide where prompts will go
  5. 2. Install Ollama and pull a model
  6. 3. Let the Open WebUI container reach Ollama
  7. 4. Start Open WebUI
  8. 5. Create the admin account, then lock down sign-up
  9. 6. Connect the model backends you chose
  10. 7. Set roles, groups and the privacy defaults
  11. 8. Put HTTPS in front with a reverse proxy
  12. 9. Back up the data and plan upgrades
  13. Alternatives to Open WebUI
  14. What this setup does not give you
  15. Troubleshooting
  16. Verify it worked
  17. Next steps
  18. FAQ
  19. How Swfte can help
  20. Sources and last verified

Short answer

To self-host a ChatGPT alternative, run Open WebUI in Docker on a private address, point it at a model you host (Ollama for small teams, vLLM for shared GPU servers), create the admin account first, then switch new sign-ups to approval. Put HTTPS in front, back up the data volume and pin the image version. Privacy depends on the model backend, not the interface.

The steps at a glance

  1. Decide where prompts will go
  2. Install Ollama and pull a model
  3. Let the Open WebUI container reach Ollama
  4. Start Open WebUI
  5. Create the admin account, then lock down sign-up
  6. Connect the model backends you chose
  7. Set roles, groups and the privacy defaults
  8. Put HTTPS in front with a reverse proxy
  9. Back up the data and plan upgrades

Before you start

Who this is for

  • IT leads and engineers setting up a private chat interface for a team, a department or a pilot.
  • Anyone who wants a ChatGPT-style experience where prompts stay on infrastructure they control.
  • Teams who already have Ollama or a vLLM endpoint and need a front end for non-technical colleagues.

Probably not for you if

  • Teams who need governed agents, permission-aware company search and an audit trail from day one. The interface covers only part of that; see the limits section below.
  • Anyone who wants to white-label the interface for customers. Read the Open WebUI licence section first.

Prerequisites

  • A Linux server or workstation with Docker installed. The commands below use Linux.
  • A model backend you control. This guide uses Ollama; if you have a vLLM server, how to self-host an LLM sets one up.
  • A hostname for the interface if more than one person will use it, and the ability to open a firewall port.
  • An email-style admin identity you can keep: the first account created becomes the administrator.
Time
About 1 to 2 hours for a working pilot, plus time for single sign-on and a short policy for users.
Cost
Free software. You pay for the server, power and the time to maintain it. Hosted model APIs, if you connect any, are billed by their providers.
Hardware
The interface itself is light. The model is what needs memory: a small model on a modern laptop or workstation for a pilot, a GPU server for a shared team.
Skill
Comfortable with Docker and the command line.

Estimates are ours, not measurements, and move with your hardware, data and network.

The Open WebUI licence: read it if you will rebrand

Open WebUI is free to run, but its licence is not a plain open-source one. From v0.6.6 (19 April 2025) it adds a branding clause: you may not alter, remove or obscure the "Open WebUI" branding unless you have 50 or fewer users in a 30-day period, or have permission or an enterprise licence. The project's own page says that licence is not OSI-approved. Versions up to v0.6.5 stayed under BSD-3-Clause.

For an internal tool that keeps the branding, this changes little. If you plan to rebrand for a larger group or for customers, read the licence text and ask the project. This is orientation, not legal advice.

  1. Step 1Decide where prompts will go

    You end up with: A written choice of model backend, because it decides your privacy, not the chat interface.

    Open WebUI is an interface. The model behind it generates the text, and wherever that model runs is where your prompts are sent. A self-hosted interface pointed at a hosted API still sends every prompt to that provider. Sometimes that is what you want. Decide on purpose.

    For a pilot, Ollama on the same machine is the shortest path: prompts never leave the box. For a shared team, a vLLM server on a GPU machine handles many users better. For tasks the data class allows, you can add a hosted model later through a gateway. Write the choice into your acceptable-use note so users know which data may go where.

    BackendWhere prompts goGood forWatch out for
    Ollama on the same hostStay on the hostPilots, small teams, laptops and workstationsLimited concurrency; one person's long request can slow others
    vLLM on a GPU server you runStay on your networkShared teams with real concurrencyYou now operate a GPU server
    A hosted APIGo to that providerHard tasks that your data policy allowsAnyone with a key can send data out; control keys centrally
  2. Step 2Install Ollama and pull a model

    You end up with: A model answers from the command line and over Ollama's local API.

    On Linux, the Ollama documentation gives a one-line installer, and the service runs under systemd. Pull a model, run it once to see that it works, then test the API. The Ollama quickstart uses gemma4:e2b as its example, which is a small model suited to a first test. Pick a larger one later once you know how much memory you have; our guide to running LLMs locally covers sizing.

    By default Ollama listens on 127.0.0.1 port 11434. That is the right default; you will change it in the next step only if you need to.

    Install Ollama (Linux) · bash
    curl -fsSL https://ollama.com/install.sh | sh
    Check the service · bash
    sudo systemctl status ollama
    Download and try a small model (type /bye to leave) · bash
    ollama pull gemma4:e2b
    ollama run gemma4:e2b
    Test the REST API · bash
    curl http://localhost:11434/api/chat \
      -H "Content-Type: application/json" \
      -d '{"model": "gemma4:e2b", "messages": [{"role": "user", "content": "Say hello in one sentence."}], "stream": false}'

    Checked against: Ollama Linux install, Ollama quickstart, Ollama FAQ

  3. Step 3Let the Open WebUI container reach Ollama

    You end up with: Ollama is reachable from Docker, and still not reachable from the wider network.

    Open WebUI will run in a container, and the container cannot see 127.0.0.1 on the host. The Open WebUI troubleshooting page gives three fixes for the common "server connection error": run the container with --network=host, set OLLAMA_HOST=0.0.0.0 so Ollama accepts connections beyond localhost, or use host.docker.internal as the hostname. The quick-start command already adds --add-host=host.docker.internal:host-gateway for that third route.

    The Ollama FAQ shows how to set the variable for a systemd service: edit the service with systemctl edit ollama.service, add the environment line, then reload and restart. Be careful with what this does. Ollama has no login. Listening on 0.0.0.0 makes it answer anyone who can reach port 11434, so block that port at the firewall for everything except the Docker network.

    If you would rather avoid this step entirely, Open WebUI publishes an image with Ollama bundled in (the :ollama tag). It is simpler, but it ties the model and the interface together in one container, which is harder to scale and upgrade separately.

    Open the service override and add the lines below · bash
    sudo systemctl edit ollama.service
    Add this under [Service] in the editor · text
    [Service]
    Environment="OLLAMA_HOST=0.0.0.0:11434"
    Apply it · bash
    sudo systemctl daemon-reload
    sudo systemctl restart ollama

    Checked against: Ollama FAQ, Open WebUI connection error troubleshooting, Open WebUI Docker quick start

  4. Step 4Start Open WebUI

    You end up with: Open WebUI runs on localhost:3000 with its data in a named volume and a persistent secret key.

    Generate a secret key first. The Open WebUI documentation says the key must persist: without it, every time the container is recreated everyone is logged out. Then run the container.

    This is the default command from the Open WebUI quick start with three changes. The port binds to 127.0.0.1 so nothing is exposed until your proxy is ready. OLLAMA_BASE_URL points at the host through host.docker.internal. And you should replace :main with a specific version tag for anything beyond a trial; the docs say :main is a rolling tag, and the update page warns it "can include breaking changes without warning". Look up the current release tag on the project's releases page and use that.

    The open-webui volume holds your chats, users and settings. The documentation puts it bluntly: never run without it.

    Create a secret key · bash
    export WEBUI_SECRET_KEY="$(openssl rand -hex 32)"
    echo "$WEBUI_SECRET_KEY"   # store this in your password manager
    Run Open WebUI · bash
    docker run -d -p 127.0.0.1:3000:8080 \
      --add-host=host.docker.internal:host-gateway \
      -v open-webui:/app/backend/data \
      -e WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" \
      -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
      --name open-webui --restart always \
      ghcr.io/open-webui/open-webui:main
    With an NVIDIA GPU, the quick start uses the :cuda image and --gpus all · bash
    docker run -d -p 127.0.0.1:3000:8080 --gpus all \
      --add-host=host.docker.internal:host-gateway \
      -v open-webui:/app/backend/data \
      -e WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" \
      -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
      --name open-webui --restart always \
      ghcr.io/open-webui/open-webui:cuda

    Checked against: Open WebUI Docker quick start, Open WebUI environment variable reference, Open WebUI updating guide, Docker port publishing

  5. Step 5Create the admin account, then lock down sign-up

    You end up with: You are the administrator, and new people cannot get in without approval.

    Browse to http://localhost:3000 and sign up. The Open WebUI roles documentation says the very first account on a fresh installation is automatically given the Admin role. That makes the first sign-up an important moment: do it yourself, straight after the container starts, before anyone else knows the address.

    Later sign-ups get the Pending role by default, which has no access until an admin approves it. The environment reference lists DEFAULT_USER_ROLE with options pending, user and admin, and a default of pending, and ENABLE_SIGNUP for toggling account creation. One quirk catches people out. Settings marked as persistent config apply from the environment only on the first launch; after that the value stored in the database wins. So to change sign-up behaviour later, use the admin settings in the interface, or set ENABLE_PERSISTENT_CONFIG to False and accept that changes made in the UI will then not be saved.

    If you will use single sign-on, plan it now. The reference documents ENABLE_OAUTH_SIGNUP (default False) and notes that OPENID_PROVIDER_URL should be set for the Google and Microsoft sign-in options, otherwise logout may not work. Follow the provider-specific section in the environment reference for the rest of the variables.

    Checked against: Open WebUI roles, Open WebUI environment variable reference

  6. Step 6Connect the model backends you chose

    You end up with: The model picker lists your models, and only the backends you approved.

    Ollama models appear on their own once OLLAMA_BASE_URL is right. For anything else, the Open WebUI documentation says adding a provider is "as simple as entering a URL and API key" in Settings, Admin, Connections. For an OpenAI-compatible server such as vLLM, the base URL ends in /v1.

    You can also set these by environment variable. OPENAI_API_BASE_URL defaults to https://api.openai.com/v1, and OPENAI_API_KEY holds the key. Take that default seriously. If someone puts a hosted key in there, prompts go to that provider, so decide who may add connections, and keep provider keys in one place under an owner. A gateway in front of all model traffic is the clean answer once you have more than one backend; see how to set up an LLM gateway.

    Test with a sentence that contains nothing sensitive, then check on the model server that the request arrived there. That is how you prove where prompts actually go.

    Example: connect a vLLM server on the same host by environment variable · bash
    docker rm -f open-webui
    docker run -d -p 127.0.0.1:3000:8080 \
      --add-host=host.docker.internal:host-gateway \
      -v open-webui:/app/backend/data \
      -e WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" \
      -e OPENAI_API_BASE_URL=http://host.docker.internal:8000/v1 \
      -e OPENAI_API_KEY="$VLLM_KEY" \
      --name open-webui --restart always \
      ghcr.io/open-webui/open-webui:main
    Check the Ollama OpenAI-compatible endpoint if you prefer to connect to Ollama that way · bash
    curl http://localhost:11434/v1/models

    Checked against: Open WebUI: connect a provider, Open WebUI environment variable reference, Ollama OpenAI compatibility

  7. Step 7Set roles, groups and the privacy defaults

    You end up with: People have the access they need and no more, and admins cannot casually read chats.

    Open WebUI separates roles (Admin, User, Pending) from groups and permissions. Roles set the baseline trust level. Groups organise users and grant additional permissions or shared access to resources, and permissions are granular feature flags such as whether a user can delete chats or use web search. The model is additive: users start with their default rights and group membership adds capabilities. So keep the default role minimal and grant more through groups.

    Admin access to other people's conversations is not automatic. The documentation says that the ENABLE_ADMIN_CHAT_ACCESS=False variable can stop admins viewing user chats. Decide your position on this before you tell staff the tool is private, and tell them what you chose. If your policy needs administrators to review conversations, say so in the acceptable-use note instead of leaving people to assume.

    Finally, write a short note for users that says which data classes may be entered, which models are connected and where they run, how long chats are kept, and who to ask for help. A one-page note does more for privacy than most settings.

    Checked against: Open WebUI RBAC overview, Open WebUI roles

  8. Step 8Put HTTPS in front with a reverse proxy

    You end up with: Users reach the interface at https://chat.example.com, and the container port is not exposed.

    Browsers and password managers behave properly only over HTTPS, and sign-in tokens should not cross a network in clear text. Caddy keeps this short: it provisions certificates automatically for a public domain name. The Caddy quick start shows a site address followed by a reverse_proxy line, then caddy run from the same directory. Caddy's documentation also states that its proxy supports WebSocket connections, which chat interfaces use for streaming.

    If the server has no public DNS name, automatic certificates will not work. Use an internal certificate authority or your organisation's existing proxy and certificate process instead. Whatever you use, open the firewall for the proxy port only, and leave port 3000 bound to 127.0.0.1 as in step 4.

    Caddyfile (replace the hostname) · text
    chat.example.com {
    	reverse_proxy localhost:3000
    }
    Start Caddy from the directory with the Caddyfile · bash
    caddy run

    Checked against: Caddy reverse proxy quick start, Caddy reverse_proxy directive

  9. Step 9Back up the data and plan upgrades

    You end up with: A tested backup and a known routine for updating the interface.

    Back up before every upgrade. The Open WebUI update page warns that database migrations are one-way: rolling back to an older version will not undo them, so the only safe rollback is to restore from a backup taken before the update. It gives a backup command that archives the volume with a throwaway container.

    The update itself is: remove the container, pull the image, run the same command again. Your data persists in the volume. Pin the version tag so that "update" means a version you chose, tested on a copy first if the interface matters to many people.

    Test the restore once. A backup that has never been restored is a guess.

    Back up the data volume · bash
    docker run --rm -v open-webui:/data -v "$(pwd)":/backup \
      alpine tar czf /backup/openwebui-$(date +%Y%m%d).tar.gz /data
    Update: remove, pull, recreate (use the same flags as step 4) · bash
    docker rm -f open-webui
    docker pull ghcr.io/open-webui/open-webui:main

    Checked against: Open WebUI updating guide

Alternatives to Open WebUI

LibreChat is the main alternative. Its repository states an MIT licence and lists multi-user authentication with OAuth2, LDAP and email login, Model Context Protocol tool support and agents. The documented Docker route is git clone https://github.com/LibreChat-AI/LibreChat.git, cd LibreChat, cp .env.example .env, then docker compose up -d, with the app on http://localhost:3080, and docker compose pull followed by docker compose up to update. Choose it if you want one front end across many providers under a permissive licence.

Our comparison of Open WebUI, LibreChat and AnythingLLM covers the differences in more depth. This guide sticks to Open WebUI because it is the closest match to the ChatGPT experience with a local model engine.

What this setup does not give you

The interface is only part of the work. After this guide you have private chat. You do not yet have permission-aware search over company documents, because built-in document chat indexes what you give it and respecting source permissions is your integration work. You do not have an audit record, since chat history is not evidence. You do not have governed agents, which need scoped tool access and approval steps. And you have a service to patch, back up and support.

If those are requirements, plan them early. See how to build a company brain for AI for the retrieval side and how to govern AI agents for the control side.

Troubleshooting

What you seeLikely causeFix
Open WebUI shows "Server Connection Error" or no Ollama modelsThe container cannot reach Ollama on the host, usually because Ollama listens only on 127.0.0.1.Set OLLAMA_HOST=0.0.0.0:11434 on the Ollama service (step 3), keep --add-host=host.docker.internal:host-gateway, and use http://host.docker.internal:11434 as the base URL. The troubleshooting page also offers --network=host; then use OLLAMA_BASE_URL=http://127.0.0.1:11434.
Everyone is logged out each time the container is recreatedNo persistent WEBUI_SECRET_KEY was set.Set the same WEBUI_SECRET_KEY on every run, as in step 4, and store it in a password manager.
You changed ENABLE_SIGNUP or another setting in the command and nothing changedPersistent config: after the first launch, the stored database value takes precedence over the environment.Change it in the admin settings, or set ENABLE_PERSISTENT_CONFIG to False if you want environment variables to always win.
New colleagues sign up but see nothingNew accounts get the Pending role until an admin approves them (the default).Approve the account in the admin user list, or set a different default role if your policy allows it.
The model list is empty after you added a vLLM connectionThe URL is missing the /v1 suffix, the key is wrong, or the container cannot reach the host port.Use http://host.docker.internal:8000/v1, send the key you set with --api-key, and test the same URL from inside the container network.
Chats are lost after an updateThe container ran without the data volume mounted.Always mount -v open-webui:/app/backend/data. Restore from your backup if you have one, and note that migrations cannot be rolled back.
The page loads but streaming responses stall behind a proxyThe proxy is buffering responses or not passing WebSocket upgrades.The Caddy documentation says its proxy supports WebSocket connections. With another proxy, allow upgrade requests and disable response buffering for the chat path.

Verify it worked

Next steps

Related guides

Frequently asked questions

What is the best self-hosted ChatGPT alternative?

There is no single best. Open WebUI is closest to the ChatGPT experience with local models. LibreChat is strongest for many providers under an MIT licence. Pilot two against your own requirements and users before you commit.

Is Open WebUI really open source?

Its code is public and free to run, but from v0.6.6 it carries a branding clause, and the project's own licence page says it is not an OSI-approved open-source licence. For internal use that keeps the branding the practical effect is small.

Is a self-hosted ChatGPT alternative private by default?

The interface runs on your server, but privacy depends on the model backend. With a model you host, prompts stay on your infrastructure. If you connect a hosted API, prompts go to that provider.

Can I use Open WebUI with Ollama and vLLM?

Yes. Open WebUI connects to Ollama through OLLAMA_BASE_URL and to any OpenAI-compatible server, including vLLM, through a connection URL ending in /v1 and an API key.

Do I need a GPU to run a private ChatGPT?

Not for a pilot with a small model on a modern workstation, and not at all if you point the interface at an API. A shared team with larger models needs a GPU server. The interface itself needs little.

Who is the administrator in Open WebUI?

The first account created on a fresh installation is automatically the Admin. Later sign-ups are Pending until approved, by default. Create your admin account yourself immediately after the first start.

How Swfte can help

This guide works without Swfte. If you want the layers around the chat window, Swfte has a governed desktop client and a model gateway.

  • Cortex: a governed AI desktop that runs local by default and answers from company files
  • Swfte Connect: the gateway that controls provider access and logs model traffic
  • Company brain platform page: the knowledge layer behind a company-wide assistant

The company brain is partly in progress: asking questions across company documents is not yet generally available. Check the platform page for current status.

Missing a step or found a command that no longer works? Tell us, or request a how-to.

Sources and last verified

Commands, versions and facts in this guide were checked against the sources below on . Tools change quickly: if something differs from what you see, trust the official documentation and let us know.

  1. Open WebUI Docker quick start: docker run commands, :main, :cuda and :ollama images, data volume, WEBUI_SECRET_KEY advice, version pinning advice
  2. Open WebUI environment variable reference: OLLAMA_BASE_URL, OPENAI_API_BASE_URL, OPENAI_API_KEY, WEBUI_SECRET_KEY, ENABLE_SIGNUP, DEFAULT_USER_ROLE, ENABLE_OAUTH_SIGNUP, OPENID_PROVIDER_URL, persistent config behaviour
  3. Open WebUI: connect a provider: adding providers in Settings, Admin, Connections
  4. Open WebUI roles: first account is Admin, Pending role, ENABLE_ADMIN_CHAT_ACCESS
  5. Open WebUI RBAC overview: roles, groups, permissions, additive model
  6. Open WebUI connection error troubleshooting: --network=host, OLLAMA_HOST=0.0.0.0, host.docker.internal, base URL fixes
  7. Open WebUI updating guide: backup command, one-way migrations, pinned versions, docker update commands
  8. Open WebUI licence page: branding clause, 50 user threshold, not OSI-approved, v0.6.6 date
  9. Ollama Linux install: install script, systemctl status ollama
  10. Ollama quickstart: ollama pull and run with gemma4:e2b, /api/chat curl example
  11. Ollama FAQ: default bind 127.0.0.1:11434, OLLAMA_HOST, systemd environment override steps
  12. Ollama OpenAI compatibility: base URL http://localhost:11434/v1/, /v1/models
  13. Docker port publishing: 127.0.0.1 port binding and default all-address publishing
  14. Caddy reverse proxy quick start: Caddyfile with a site address and reverse_proxy, caddy run
  15. Caddy reverse_proxy directive: WebSocket connections supported
  16. LibreChat Docker setup: git clone, .env copy, docker compose up -d, port 3080, update commands
  17. LibreChat repository: MIT licence, OAuth2 LDAP email login, MCP support, agents

Topics

  • open webui
  • ollama
  • chat interface
  • self-hosting
  • team workspace

Machine-readable copies: this guide as markdown, index of all guides (JSON). Canonical address: https://www.swfte.com/how-to-self-host-chatgpt-alternative.

Deploy a model with Swfte Connect

One gateway, every provider, per-token cost visibility. Swap models without touching your code.