AILLMSelf-HostingAI Coding Agents
Jan in 2026: Private Offline ChatGPT With a Local API (Linux, Windows, Mac)
Before you start
- 16 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#
Jan is a free, open-source desktop app that runs AI models on your own computer, so your chats stay private and work without internet. It also starts a local OpenAI-compatible API on your machine.

Logo: the official Jan project (github.com/janhq/jan)
Think of it as ChatGPT in a window on your own PC. You download a model once, then chat, attach files and connect tools without sending anything out. Other programs can use the same model through the local API, with the same code you would write for OpenAI.
One thing first, said plainly: Jan is a desktop app. It has no official Docker image and no official server mode. We looked in the README, the docs and the release files, and found installers only (.exe, .dmg, .deb, AppImage and Flatpak). So this guide installs it like any app, per system. Docker only appears as an optional extra later.
At a glance#
- What you get: a private chat app, a model library (Hub) and a local API at
http://127.0.0.1:1337/v1. - Time needed: about 20 minutes, most of it downloading.
- Difficulty: easy. You run an installer, click a few buttons and copy one test command.
- You need: a 64-bit PC or an Apple Silicon Mac, 8 GB RAM or more, 10 GB free disk space.
- Offline? Yes, with local models. Anything you send to a cloud provider you add leaves your machine.
| What | Value |
|---|---|
| Current version | v0.8.7, released 20 Oct 2026 (GitHub releases) |
| Download size | about 560 MB (Windows), 1 GB (Linux .deb), 105 MB (Mac) before models |
| Licence | Apache 2.0 |
| Local API | http://127.0.0.1:1337/v1 (OpenAI-compatible) |
| Docker image | none (desktop app) |
| Official docs | jan.ai/docs/desktop |
Why this version? We checked the issue tracker for v0.8.7. We found a few single bug reports and no pattern of install failures or data loss. The release notes say your data and settings carry over. So this guide uses the latest release. Two cautions: do not use 0.8.5 (its Linux AppImage crashed on every model load and some older NVIDIA cards failed; 0.8.6 fixed both), and Intel Macs cannot run local models from 0.8.5 on.
How it fits together#
You and your own scripts both talk to the Jan app. Jan runs the model with its built-in llama.cpp engine and keeps models and chats in its data folder.
Two simple rules:
- The local API is off until you start it, and it listens on
127.0.0.1(this computer only) by default. - A cloud provider is optional. If you add one, that chat is no longer offline.
Before you start#
Any recent 64-bit system works, as long as it has enough memory for the model you choose.
| System | Needs (from the Jan docs) |
|---|---|
| Linux | Debian/Ubuntu, Fedora/RHEL, Arch or openSUSE. CPU with AVX2 (Intel Haswell 2013+, AMD Excavator 2015+). 8 GB RAM minimum, 16 GB recommended. 10 GB free disk |
| Windows | Windows 10 or higher, x64 with AVX2 (or ARM64). 8 GB RAM minimum, 16 GB recommended. 10 GB free disk. NVIDIA, AMD or Intel Arc GPUs are supported |
| Mac | macOS 13.6 or higher on Apple Silicon (M1 or newer). 10 GB+ free disk. Intel Macs cannot run local models since 0.8.5 |
You do not need the CUDA Toolkit: Jan bundles CUDA 13. GPUs or drivers that cannot use it fall back to Vulkan, so keep a current graphics driver installed. Docker and WSL2 are not needed.
Checklist:
- [ ] You have 10 GB free (models add more)
- [ ] Your graphics driver is up to date
- [ ] Port 1337 is free (Jan does not pick another port by itself)
- [ ] You know where your important files are (nothing here touches them)
Tested on 2026-10-26: not run. Commands and settings checked against the official Jan docs and the v0.8.7 release files.
Step 1: Install Jan#
Download the installer for your system and run it. Check the file against the hash GitHub shows next to the download on the release page if you like.
Linux#
Flatpak is the way the Jan docs recommend. It works on any distribution and updates with your system:
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo flatpak install flathub ai.jan.Jan flatpak run ai.jan.Jan
Prefer a .deb (Ubuntu or Debian)?
cd /tmp curl -LO https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_amd64.deb sudo apt-get install ./Jan_0.8.7_amd64.deb
The AppImage also works: download Jan_0.8.7_amd64.AppImage from the release page, run chmod +x on it and start it. The .deb does not auto-update, and the in-app updater is switched off for Flatpak.
Windows (PowerShell)#
curl.exe -L -o "$env:TEMP\Jan-setup.exe" https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_x64-setup.exe Start-Process "$env:TEMP\Jan-setup.exe"
On a Windows on ARM PC, use Jan_0.8.7_arm64-setup.exe instead. Use curl.exe, not curl: in Windows PowerShell 5 plain curl is an alias for another command.
Mac (Terminal)#
cd ~/Downloads curl -LO https://github.com/janhq/jan/releases/download/v0.8.7/Jan_0.8.7_universal.dmg open Jan_0.8.7_universal.dmg
Drag Jan to Applications and open it.
Check it worked#
Jan opens a guided first-run wizard (welcome, engine setup, a first model, then a consent page). If you see it, the install is fine. Potential issue: a blank window or a crash on launch is covered in Troubleshooting.
Step 2: Download a model that fits your memory#
Open the Hub in Jan, search for a model and download it. Pick one that is smaller than about 80% of your RAM.
The Jan troubleshooting page gives the rule: keep the model under roughly 80% of your memory. That is about 6 GB on an 8 GB machine and 13 GB on a 16 GB machine. The sizes below are our rough guide for 4-bit models, not official numbers. Check each model's page.
| Your memory | Try a model of about |
|---|---|
| 8 GB RAM, 4-6 GB VRAM | 3-4 billion parameters, Q4 |
| 16 GB RAM, 8-12 GB VRAM | 7-9 billion parameters, Q4 or Q5 |
| 32 GB RAM or more, 16-24 GB VRAM | 14-32 billion parameters, Q4 |
On a Mac the docs say 8 GB suits up to about 3B models, 16 GB about 7B and 32 GB about 13B.
Open Jan first. The model steps are the same in the Jan window on every system:
Linux#
Start Jan from your app menu (Flatpak: flatpak run ai.jan.Jan).
Windows (PowerShell)#
Start Jan from the Start menu.
Mac (Terminal)#
open -a Jan
Then in the Jan window:
- Click Hub, search, and download a model from HuggingFace.
- Or import your own
.gguffile. For a model split into several files, point Jan at shard 1. - The default context size is 8192 and can go up to 131072. A bigger context needs more memory, so lower it if you run out.
Check it worked#
Start a new chat, choose the model, and say hello. A reply means the engine loaded it. Open Settings > Hardware > GPUs to see whether your GPU is switched on.
Step 3: Start the local API and call it#
In Settings, pick a default model and start the server. Then one curl command proves it works.
- Open Settings > Local API Server.
- Under Default Model choose your local model.
- Set an API Key (any string you invent, such as a long random password). If you leave it empty, no key is needed, so always set one.
- Click Start Server.
The base URL is http://127.0.0.1:1337/v1. Find your model ID with /v1/models (or copy it in Jan).
Linux#
curl http://127.0.0.1:1337/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"
curl http://127.0.0.1:1337/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-d '{"model":"<YOUR_MODEL_ID>","messages":[{"role":"user","content":"Tell me a joke."}]}'
Windows (PowerShell)#
$h = @{ Authorization = "Bearer <YOUR_API_KEY>" }
$b = '{"model":"<YOUR_MODEL_ID>","messages":[{"role":"user","content":"Tell me a joke."}]}'
Invoke-RestMethod http://127.0.0.1:1337/v1/chat/completions -Method Post -Headers $h -ContentType "application/json" -Body $b
Mac (Terminal)#
Same commands as Linux.
Check it worked#
You get a JSON answer with a choices list holding the model's reply. Expected shape (from the OpenAI format Jan follows, not a real capture):
{"object":"chat.completion","choices":[{"message":{"role":"assistant","content":"..."}}], ...}
The server settings, all from the official API docs:
| Setting | Default | What it does |
|---|---|---|
| Server host | 127.0.0.1 | Only this computer. 0.0.0.0 opens it to your whole network |
| Server port | 1337 | Change it if the port is taken |
| API prefix | /v1 | OpenAI-style path |
| API key | empty (off) | Needed in Authorization: Bearer when set |
| Trusted hosts | empty | Host names allowed to call the server |
| CORS | on | Switch off if only scripts (not web pages) use the API |
| Execute tools on server | off | Runs MCP tool calls on the server side |
The API server needs a local model to start. On Windows and Linux, closing the window keeps the server running if the "Run in background" option is on.
Optional: cloud providers, MCP and the tools#
Jan can also talk to cloud models and use tools, but both are optional.
- Cloud providers: add one under Settings > Model Providers with its key and base URL (usually ending in
/v1). Requests to it leave your machine, so that chat is not offline. - MCP (connectors): Jan supports MCP servers, so a model can call tools such as search. Only add servers you trust.
- Shell tool: chat has a sandboxed shell tool. Since 0.8.7 you can switch it off from the tool menu in the message box.
- Provider keys are kept in your operating system's keyring since 0.8.4, not in plain browser storage.
How Jan compares#
Pick Jan if you want a friendly desktop app. Pick Ollama with Open WebUI if you want a server with several users.
| Jan | Ollama + Open WebUI | LM Studio | |
|---|---|---|---|
| Form | Desktop app | Daemon plus web page | Desktop app |
| Licence | Apache 2.0 | Open source | Closed-source app |
| OpenAI-style API | Yes, port 1337 | Yes, port 11434 | Yes, port 1234 |
| Official Docker or server mode | No | Yes | Not checked |
| Several users | No | Yes (Open WebUI) | No |
| Cloud models in the same app | Yes | Limited | Limited |
The Jan column comes from the official docs. The other two are our general summary, not official claims. We have an Ollama guide too.
Optional: put a web page in front with Docker#
This is an extra, not part of Jan. If you want a browser chat page for other people, you can run Open WebUI in Docker and point it at Jan's API. We have a full Open WebUI and Ollama guide for the container side. The two Jan-specific settings are the API address and your key, for example:
services:
open-webui:
image: ghcr.io/open-webui/open-webui:<pinned-tag>
container_name: open-webui
restart: unless-stopped
ports:
- "127.0.0.1:3000:8080"
environment:
OPENAI_API_BASE_URL: http://host.docker.internal:1337/v1
OPENAI_API_KEY: ${JAN_API_KEY}
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ~/docker_volumes/open-webui/data:/app/backend/data
Jan must listen on 0.0.0.0 for a container to reach it, so set an API key and the trusted hosts first. Take the pinned tag from the Open WebUI releases page. We did not test this file.
Put it behind HTTPS (with or without Traefik)#
Most people never need this. Jan's API listens on this computer only, and that is the safest setting. Read on only if other devices must use your API. Then you put a reverse proxy in front, so the key is not sent in plain text.
Rules for both routes:
- Keep Jan on
127.0.0.1when the proxy runs on the same computer. - Add the public host name to Trusted Hosts in Jan. If other devices get
403, this is why. - Never forward port 1337 to the internet.
With Traefik#
Choose this if Traefik already runs on this computer in Docker. Jan is not a container, so Traefik needs a file-provider route to the host. This is our example, not from the official docs (VERIFY against your Traefik setup). Jan must listen on 0.0.0.0 for a container to reach it.
# dynamic config file, e.g. ~/docker_volumes/traefik/config/jan.yml
http:
routers:
jan:
rule: "Host(`jan.<your-domain>`)"
entryPoints: [https]
tls: {}
service: jan
services:
jan:
loadBalancer:
servers:
- url: "http://host.docker.internal:1337"
Add extra_hosts: ["host.docker.internal:host-gateway"] to the Traefik service, and your domain, DNS and ports 80 and 443 must already work.
Without Traefik: Caddy#
Choose Caddy if you have no Traefik yet. It runs next to Jan, so Jan can stay on 127.0.0.1.
| Case | Result | You do |
|---|---|---|
| Public domain | Automatic Let's Encrypt | DNS A record to this computer, ports 80 and 443 open |
| Home only | tls internal (Caddy's local certificate) | Trust Caddy's root certificate on each device |
Caddyfile for a public domain:
jan.example.com {
reverse_proxy 127.0.0.1:1337
}
Caddyfile for home only (point the name at the Caddy computer):
jan.home.arpa {
tls internal
reverse_proxy 127.0.0.1:1337
}
Trust the root certificate (pki/authorities/local/root.crt in Caddy's data folder):
# Linux: on the Caddy machine sudo caddy trust # other Linux devices, with root.crt copied over sudo cp root.crt /usr/local/share/ca-certificates/caddy-root.crt && sudo update-ca-certificates # Mac sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root.crt
# Windows (PowerShell as administrator) certutil -addstore -f ROOT root.crt
Run Caddy:
# Linux: install from the official apt repository (caddyserver.com/docs/install), then sudo systemctl reload caddy # Mac brew install caddy && caddy run --config Caddyfile
# Windows (PowerShell) winget install CaddyServer.Caddy caddy run --config Caddyfile
Or use the official image caddy:2.11.7 (Jan must then listen on 0.0.0.0, and the Caddyfile uses reverse_proxy host.docker.internal:1337). Save the Caddyfile as ~/docker_volumes/caddy/conf/Caddyfile. Create the folder first: mkdir -p ~/docker_volumes/caddy/conf (Windows PowerShell: New-Item -ItemType Directory -Force "$HOME\docker_volumes\caddy\conf"). Caddy gets the whole conf folder, not one file, because Caddy's Docker docs warn that editors can break a single-file mount.
services:
caddy:
image: caddy:2.11.7
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ~/docker_volumes/caddy/conf:/etc/caddy:ro
- ~/docker_volumes/caddy/data:/data
- ~/docker_volumes/caddy/config:/config
Check it worked:
curl -I https://jan.example.com/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"
Expected: HTTP/2 200. A 401 means the key is missing, a 403 means the host is not in Trusted Hosts.
Security and testing#
Keep the API on this computer, always use a key and keep secrets out of scripts.
- Default is safest: host
127.0.0.1. Use0.0.0.0only on a trusted home network, with an API key and Trusted Hosts. Version 0.8.5 fixed a flaw so Trusted Hosts is enforced on0.0.0.0, so stay on 0.8.5 or newer (GitHub advisory GHSA-x6p8-7cp8-c3p6, as reported by Perplexity; VERIFY). - Never port-forward 1337 to the internet.
- Key in a file, not in the script. Save it in an environment variable or a
.envfile and lock it:
echo 'JAN_API_KEY=<YOUR_API_KEY>' > ~/.jan-env && chmod 600 ~/.jan-env
- Switch CORS off if only scripts call the API.
- Download from the official release page only, and compare the hash.
Tests:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1337/v1/models
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1337/v1/models -H "Authorization: Bearer <YOUR_API_KEY>"
Expected: the first prints 401 (a key is set and you sent none), the second prints 200.
Troubleshooting#
| Problem | Solution |
|---|---|
401 Unauthorized | Send Authorization: Bearer <YOUR_API_KEY> |
404 Not Found | Check the model ID and the /v1 prefix |
403 from another device | Add the host name to Trusted Hosts in Local API Server settings |
Address already in use on 127.0.0.1:1337 | Quit the old Jan process, or change the port. Jan does not pick another port |
| Blank window or crash on launch | Fully quit Jan, rename store.json in the data folder, start again |
The provided PTX was compiled with an unsupported toolchain | Old NVIDIA GPU on v0.8.5: update to v0.8.6 or newer |
unknown model architecture | The engine is too old for that model: update Jan |
failed to allocate ... buffer, out of memory, cudaMalloc | Smaller model, lower context, fewer GPU layers |
request (N tokens) exceeds the available context size | Raise the context size |
jan-llama-worker did not report a port within ... | Slow load (timeout 600 s): wait, or use a smaller model or a faster disk |
Where the logs live (logs/app.log inside the data folder):
| System | Path |
|---|---|
| Linux (.deb / AppImage) | ~/.local/share/Jan/data/logs/app.log |
| Linux (Flatpak) | ~/.var/app/ai.jan.Jan/data/Jan/data/logs/app.log |
| Windows | %APPDATA%\Jan\data\logs\app.log |
| Mac | ~/Library/Application Support/Jan/data/logs/app.log |
Since 0.8.5 the engine runs in its own process called jan-llama-worker, so look for that name in the log when a model fails to load. Redact private details before you share a log.
Known bugs#
Open on GitHub when we read it (2026-10-26):
- #9435: on Windows the
jan-llama-workerprocess can hang on "Working" after MCP tool calls. If you hit it, switch off your MCP servers. - #9407: the bundled engine cannot be updated separately. You wait for an app update to support brand-new models.
- #9317: long chats with remote models can fail with "prompt is too long" because auto-compact does not run for them.
- Intel Macs: no local models since 0.8.5 (official docs).
Updates and backups#
Update from the app (or Flatpak), and back up the data folder.
- Windows, Mac and AppImage: Jan updates itself. Check the release notes first, especially the Migration part when you jump several versions.
- Linux Flatpak:
flatpak update ai.jan.Jan. - Linux .deb: no auto-update. Download the new .deb and install it the same way as before.
Your data and settings are kept across reinstalls. Back up anyway. Models make the archive huge, so skip them and download them again if needed (they live in llamacpp/models in the data folder).
Linux#
mkdir -p ~/docker_volumes/jan-backup tar czf ~/docker_volumes/jan-backup/jan-$(date +%F).tgz \ --exclude='Jan/data/llamacpp/models' -C ~/.local/share Jan
Windows (PowerShell)#
New-Item -ItemType Directory -Force "$HOME\docker_volumes\jan-backup" | Out-Null $files = Get-ChildItem "$env:APPDATA\Jan\data" | Where-Object Name -ne 'llamacpp' Compress-Archive -Path $files.FullName -DestinationPath "$HOME\docker_volumes\jan-backup\jan-$(Get-Date -Format yyyy-MM-dd).zip" -Force
Mac (Terminal)#
mkdir -p ~/docker_volumes/jan-backup tar czf ~/docker_volumes/jan-backup/jan-$(date +%F).tgz \ --exclude='Jan/data/llamacpp/models' -C ~/Library/"Application Support" Jan
Schedule it: Linux and Mac with cron at 03:00 (0 3 * * * <path-to-script>), Windows with Task Scheduler. Quit Jan before backing up so files are not half-written.
Restore test#
Do this once, before you need it:
mkdir /tmp/jan-test && tar xzf ~/docker_volumes/jan-backup/jan-*.tgz -C /tmp/jan-test ls /tmp/jan-test/Jan/data
You should see your threads folder and logs. On a spare computer, quit Jan, move its Jan folder aside, copy the backup in, start Jan and check that your chats appear. If not, put the old folder back.
Performance and resources#
The biggest speed-up is a model that fits fully in GPU memory. We did not measure speed ourselves, because it depends on your hardware and model.
- Check Settings > Hardware > GPUs and make sure your GPU is on.
- Keep model plus context under about 80% of memory. Lower the context size if you run out.
- Since 0.8.5 each chat's prompt cache is kept on disk (default cap 8192 MiB). You can turn this off under Settings > Model Providers > Llama.cpp.
- The engine runs in its own worker process, so an engine crash does not close the app.
- Watch memory while a model runs with Task Manager (Windows), Activity Monitor (Mac) or
htop(Linux).
FAQ#
Is Jan really offline? Yes, with local models. Anything routed to a cloud provider you added leaves your machine.
Can I run Jan in Docker or headless? Not officially. Jan is a desktop app. For a headless server, run llama-server yourself or use Ollama.
Will my chats survive an update? The release notes say data and settings carry over. Back up first anyway.
Why do I get 403 from another computer? Its host name is not in Trusted Hosts. Add it in Local API Server settings.
Why can't my Intel Mac run local models? The bundled engine needs Apple Silicon since 0.8.5. Use a cloud provider there, or a newer Mac.
Can Claude Code or other tools use Jan? Any tool that accepts an OpenAI-style base URL can: give it http://127.0.0.1:1337/v1 and your key.
Sources#
- Jan Desktop docs, Local API Server, Troubleshooting, Linux, Windows, Mac, Data folder (read 2026-10-26)
- janhq/jan README and release v0.8.7 (20 Oct 2026); issues #9435, #9407, #9317
- Caddy docs: automatic HTTPS, tls internal, reverse_proxy, install (Caddy 2.11.7, read 2026-10-26)
Checked against the official docs on 2026-10-26. Not run by DIY Lab Hub. Items marked VERIFY are not confirmed in the official docs.