Server#
gptme provides multiple web-based interfaces for browser-based interactions, from lightweight options to sophisticated desktop-integrated experiences.
Installation#
To use gptme’s server capabilities, install with server extras:
pipx install 'gptme[server]'
Start the server, then open http://localhost:5700:
gptme-server
The server and modern web UI share one origin by default, so no separate frontend process or CORS configuration is required.
For more CLI options, see the CLI reference.
gptme-webui: Modern Web Interface#
The primary web interface is gptme-webui: a modern, feature-rich application that provides a complete gptme experience in your browser. (Originally a standalone repo, now merged into the main gptme repository.)
Try it now:
chat.gptme.org (latest version of gptme-webui, bring your own gptme-server)
gptme.ai (upcoming hosted gptme service)
Key Features:
Modern interface
Streaming responses
Mobile-friendly responsive design
Dark mode support
Conversation export and offline capabilities
Integrated computer use interface
Create your own persistent agents
Local use:
The modern UI is bundled in gptme release packages. Run gptme-server and
open http://localhost:5700.
For frontend development, see the gptme-webui README. When Vite runs separately on port 5701, allow that development origin:
gptme-server --cors-origin 'http://localhost:5701'
Note
Connecting the hosted web UI to a local server (Chrome 142+).
When you use the hosted web UI at chat.gptme.org
with a gptme-server running on localhost, recent Chromium browsers
(Chrome 142+) gate the connection behind a Local Network Access permission
prompt. This check runs before CORS headers are evaluated, so the
--cors-origin flag is necessary but no longer sufficient — you must also
click Allow on the permission prompt for the page to reach your local
server. Serving the web UI from a local origin (for example
http://localhost:5701) avoids the prompt entirely, since that is a
local-to-local request.
Note
Host-header validation. Bearer authentication is enabled for loopback
and network binds alike. If an operator explicitly disables authentication
with GPTME_DISABLE_AUTH, they can still opt into Host-header validation
with gptme-server serve --allowed-hosts gptme.local (comma-separated,
or via GPTME_SERVER_ALLOWED_HOSTS).
Self-Hosting with Docker Compose#
For a self-contained deployment, a docker-compose.yml is included at the
repository root. It builds a lean image (scripts/Dockerfile.selfhost,
gptme + the server extra only — no Node/agent tooling) and runs
gptme-server with persistent volumes for config and conversation logs.
# Clone the repository
git clone https://github.com/gptme/gptme.git
cd gptme
# Configure: at least one provider key is required
cp .env.example .env
$EDITOR .env
# Build and start the server
docker compose up --build
The server listens on http://localhost:5700.
The modern web UI is bundled at the same origin — just open http://localhost:5700 in a browser. Being same-origin, it needs no CORS setup (you will still need the server token; see below).
To use the hosted web UI instead, open
chat.gptme.org and point it at your server. That is
a cross-origin setup, so uncomment the Compose command and set
CORS_ORIGIN to the hosted UI (or your separately hosted UI).
Key .env settings:
OPENAI_API_KEY/ANTHROPIC_API_KEY/OPENROUTER_API_KEY— at least one is required.GPTME_SERVER_TOKEN— auth token. The server enables auth by default when bound to0.0.0.0(as in the container), so set this and configure the web UI with the same value. If left blank, a token is auto-generated at startup — find it withdocker compose logs.CORS_ORIGIN— only needed for a separately hosted web UI; uncomment the Composecommandand set this to that UI’s origin.GPTME_SERVER_PORT— host port to publish (the container always listens on 5700).
Production Deployment: nginx Reverse Proxy#
The docker-compose setup above publishes the server on a plain HTTP port
(5700 by default). For a public-facing deployment you should put it behind a
reverse proxy that terminates TLS and forwards requests to the container. The
example below uses nginx with a Let’s Encrypt certificate.
Warning
Do not expose the raw 5700 port to the internet. Bind the published
port to loopback so only the proxy can reach it. In .env (or
docker-compose.yml) set the publish address to 127.0.0.1:
ports:
- "127.0.0.1:5700:5700"
Also set GPTME_SERVER_TOKEN to a strong value — the proxy handles TLS,
but the token is what authenticates each request.
1. Obtain a TLS certificate with certbot (one-time, then auto-renewed):
sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d gptme.example.com
Note
The --nginx plugin handles the ACME HTTP challenge through nginx
itself, so you do not need to stop nginx first (unlike
--standalone, which binds its own listener to port 80 and fails
when nginx is already running).
2. nginx site config (/etc/nginx/sites-available/gptme):
server {
listen 80;
server_name gptme.example.com;
# Redirect all HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name gptme.example.com;
ssl_certificate /etc/letsencrypt/live/gptme.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gptme.example.com/privkey.pem;
# Restrict to TLS 1.2/1.3 with strong ciphers (Mozilla "intermediate" profile)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:5700;
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;
# gptme-server streams responses over Server-Sent Events
# (text/event-stream). Disable proxy buffering and use long
# read timeouts so streamed tokens are flushed to the client
# immediately rather than buffered until the response completes.
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_set_header Connection "";
proxy_http_version 1.1;
}
}
3. Enable the site and reload nginx:
sudo ln -s /etc/nginx/sites-available/gptme /etc/nginx/sites-enabled/
sudo nginx -t # validate config
sudo systemctl reload nginx
The server and bundled UI are now reachable together at
https://gptme.example.com. If you instead use a separately hosted UI such
as chat.gptme.org, set CORS_ORIGIN in .env
to that UI’s origin and enable the Compose --cors-origin command.
Note
The proxy_buffering off and long proxy_read_timeout settings are the
important part: without them nginx buffers the SSE stream and the chat appears
to hang until each full response is ready, instead of streaming token by
token.
Local-only access. If you only want the server reachable from the host
itself (for example, behind a VPN or an SSH tunnel), skip the proxy entirely and
keep the default loopback bind — open an SSH tunnel from your client with
ssh -L 5700:127.0.0.1:5700 user@host and use http://localhost:5700.
Running as a systemd Service (pipx)#
If you installed gptme directly with pipx rather than Docker, you can run
the server as a systemd service so it starts on boot and restarts on failure.
A ready-to-edit unit template ships at scripts/gptme-server.service.
The template runs the server as a dedicated gptme user, reads secrets from
/etc/gptme/server.env, binds loopback, and applies systemd hardening
(ProtectSystem=strict, NoNewPrivileges, etc.). Install it with:
# Dedicated service user + pipx install of the entrypoint
sudo useradd --system --create-home --shell /usr/sbin/nologin gptme
sudo -u gptme pipx install 'gptme[server]'
# Pre-create config/data dirs (required: ProtectHome=read-only only bind-mounts
# paths that already exist; gptme initialises them at import time, which fails
# under the sandbox on a fresh install before any request is served)
sudo -u gptme mkdir -p /home/gptme/.config/gptme \
/home/gptme/.local/share/gptme \
/home/gptme/.local/state/gptme
# Secrets file (provider keys + GPTME_SERVER_TOKEN), not world-readable
sudo install -d -m 750 -o gptme -g gptme /etc/gptme
sudo install -m 640 -o gptme -g gptme /dev/null /etc/gptme/server.env
sudoedit /etc/gptme/server.env # add ANTHROPIC_API_KEY=... etc.
# Download and install the unit (adjust User= and the ExecStart path)
sudo curl -fsSL https://raw.githubusercontent.com/gptme/gptme/master/scripts/gptme-server.service \
-o /etc/systemd/system/gptme-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now gptme-server
Tail logs with journalctl -u gptme-server -f. Because the unit binds
127.0.0.1, pair it with the nginx reverse proxy above to expose it over TLS.
Set GPTME_SERVER_TOKEN in the env file to a stable secret so clients have a
persistent credential across restarts. This is required for persistent
deployments: if omitted the server generates a new random token at each startup,
invalidating any client already configured with the previous token.
Basic Web UI#
A lightweight chat interface with minimal dependencies is bundled with the gptme server for simple deployments.
Access at http://localhost:5700 after starting gptme-server.
This interface provides basic chat functionality and is useful for:
Quick testing and development
Minimal server deployments
Environments with limited resources
Computer Use Interface#
The computer use interface provides an innovative split-view experience with chat on the left and a live desktop environment on the right, enabling AI agents to interact directly with desktop applications.
Warning
The computer use interface is experimental and has serious security implications. Please use with caution and see Anthropic’s documentation on computer use for additional guidance.
Docker Setup (Recommended):
# Clone the repository
git clone https://github.com/gptme/gptme.git
cd gptme
# Build and run the computer use container
make build-docker-computer
docker run -v ~/.config/gptme:/home/computeruse/.config/gptme -p 6080:6080 -p 8080:8080 gptme-computer:latest
Access Points:
Combined interface: http://localhost:8080/computer
Chat only: http://localhost:8080
Desktop only: http://localhost:6080/vnc.html
Features:
Split-view interface with real-time desktop interaction
Toggle between view-only and interactive desktop modes
Automatic screen scaling optimized for LLM vision models
Secure containerized environment
Requirements:
Docker with X11 support
Available ports: 6080 (VNC) and 8080 (web interface)
Local Computer Use (Advanced)#
You can enable the computer tool locally on Linux systems, though this is not recommended for security reasons.
Requirements:
X11 server
xdotoolpackage installed
Usage:
# Enable computer tool in addition to default tools
gptme --tools +computer
Set an appropriate screen resolution for your vision model before use.
For long-running visual workflows, prefer a specialized subagent profile to keep parent context smaller:
# Desktop interaction (mouse, keyboard, screenshots)
subagent(
"computer-use",
"Click the Submit button, wait for the modal, and screenshot the result",
)
# Web browsing and testing
subagent(
"browser-use",
"Open localhost:5173, capture a screenshot, and report UI issues",
)
Security#
This section describes the security model of gptme-server and the threat vectors it is designed (and not designed) to address.
Authentication Model#
gptme-server requires bearer authentication for capability-bearing API routes
regardless of bind address. Loopback is a transport boundary, not an identity
boundary: another local process must not gain shell and config access merely by
reaching 127.0.0.1. A small set of public routes remain unauthenticated: the
API root (/api/v2), version info (/api/v2/version), config metadata
(/api/v2/config), Prometheus metrics (/api/v0/metrics), and the API
documentation at /api/docs/. Set GPTME_SERVER_TOKEN to a fixed value;
if unset the server generates one and prints it at startup.
GPTME_DISABLE_AUTHdisables bearer checks entirely regardless of bind address. Use only behind an authenticated ingress.
Warning
An authorized API client (anyone who can reach the server with a valid token) can execute arbitrary shell commands through the agent. There is no additional sandboxing at the API layer. The security boundary is access to the server, not any individual endpoint.
Threat Model#
The server is hardened against browser-originating attacks that apply to local server access:
1. Cross-Site Request Forgery (CSRF)
A malicious web page cannot send credentialed cross-origin JSON requests
to the local server because the browser’s CORS preflight blocks them: the
server does not return Access-Control-Allow-Origin headers for arbitrary
origins (only for the configured --cors-origin). Plain forms can POST
without CORS, but cannot set Content-Type: application/json, so the
server rejects them as malformed.
2. DNS Rebinding
A malicious site can re-resolve its hostname to 127.0.0.1 after the page
loads and thereby bypass CORS. Bearer authentication still blocks access to
capability-bearing routes because the page does not possess the token. If an
operator explicitly disables bearer auth, --allowed-hosts can add
Host-header validation as defense in depth.
What is NOT in scope:
An authorized client redirecting the agent to sensitive files: An authorized API client can already run
cat /etc/passwdthrough the agent. Restricting which directories the agent starts in adds no security boundary — the agent can navigate anywhere from there.Protecting one user from another on a shared server: gptme-server is single-user by design. Multi-user setups must gate access at the network or OS level.
Workspace PATCH Semantics#
Conversations have a workspace — the directory the agent treats as its working directory. The API exposes two operations that touch workspace:
PUT
/api/v2/conversations/<id>(create): accepts anyworkspacethe client supplies, including paths outside the conversation’s log directory. Rationale: an authorized client can already run arbitrary shell commands; workspace containment at creation adds no security boundary. Cloud pods and the workspace picker both rely on this to set a custom workspace on create.PATCH
/api/v2/conversations/<id>/config(update): accepts the round-trip of the already-persisted workspace (the webui settings dialog sends the full config including workspace on every save), but rejects any change that redirects the workspace outside the conversation’s log directory. Rationale: silently redirecting an existing agent’s workspace mid-conversation to an arbitrary path is plausibly a confused-deputy attack vector and is never needed for legitimate updates. If the workspace must change, delete and recreate the conversation.Warning
Deleting a conversation is destructive: its persisted message history is permanently removed. Export or back up conversation logs before deleting if you need to preserve them.
This creates an intentional asymmetry — create-any, re-target-never — to minimize confused-deputy risk without breaking legitimate workflows.
REST API#
gptme-server provides a REST API for programmatic access to gptme functionality. This enables integration with custom applications and automation workflows.
The API endpoints support the core gptme operations including chat interactions, tool execution, and conversation management.
Note
API documentation is available when running the server. Visit the server endpoint /api/docs/ for interactive API documentation based on the OpenAPI spec (served at /api/docs/openapi.json).