Assistant is designed to run on a private, trusted network — typically your home server, a local VM, or a private VPS that is not directly reachable from the public internet. This document explains the security model, its inherent limitations, and what you must do if you choose to expose it beyond a private network.
Every API endpoint, the admin dashboard (/admin), and the workspace UI (/workspace) are completely unauthenticated. Anyone who can reach the server's IP and port can:
- Create, cancel, and delete jobs
- Read and write files in the shared workspace
- Browse and edit memories, notes, and contacts
- Trigger sandboxed command execution
- Access all email, calendar, and configuration data
This is an intentional design trade-off for simplicity in private deployments. It means network-level access control is your only protection.
Assistant is designed to be accessed by one person (you) on a network you control. There are three typical deployment scenarios:
Run the stack on your own laptop or desktop. The default 127.0.0.1 binding means only your machine can reach the dashboard. This is the safest default.
Run on a home server or NAS. Bind to the server's LAN IP (e.g., 192.168.1.50). Only devices on your LAN can reach the dashboard. This is safe if you trust all devices on your network.
If your server has a public IP, you must put the dashboard behind a reverse proxy with authentication before it is safe to operate. See If You Must Expose This Publicly below.
The agent-api service in docker-compose.yml publishes its port like this:
ports:
- "${AGENT_API_PUBLISHED_HOST:-127.0.0.1}:${AGENT_API_PUBLISHED_PORT:-8000}:8000"The default AGENT_API_PUBLISHED_HOST=127.0.0.1 means Docker will only accept connections on the loopback interface — the dashboard is not reachable from other machines. This is the safest default.
To allow LAN access, set in .env:
AGENT_API_PUBLISHED_HOST=192.168.1.50 # your server's LAN IPNever set AGENT_API_PUBLISHED_HOST=0.0.0.0 on a server with a public IP unless you have a firewall rule or reverse proxy blocking external access.
Inside the container, the API binds to 0.0.0.0 so that Docker's port-forwarding can route traffic to it. This does not expose the service externally — what's reachable from outside is controlled entirely by the AGENT_API_PUBLISHED_HOST setting on the Docker host (see above), which still defaults to 127.0.0.1. You can override the internal bind address in config/agent.yaml or via AGENT_API_BIND_HOST, but there is normally no reason to do so.
As a safety net, the API refuses to start if AGENT_API_BIND_HOST resolves to 0.0.0.0 unless you explicitly acknowledge this by setting:
AGENT_API_ALLOW_PUBLIC_BIND=trueOr in config/agent.yaml:
agent:
api:
allow_public_bind: trueThis prevents a casual user from accidentally exposing all unauthenticated endpoints on every network interface. In the standard Docker Compose setup the internal bind is 0.0.0.0 (so Docker port-forwarding works), and the override is already set in the container environment. If you run the API outside Docker and forget to set AGENT_API_BIND_HOST to 127.0.0.1, this guard will catch the mistake.
The .env.example file contains a placeholder password that must be changed before deploying:
Do this before starting the stack:
cp .env.example .env
# Generate a strong password, for example:
openssl rand -base64 32
# Set it in .env:
POSTGRES_PASSWORD=<your-generated-password>The application will log a startup warning if it detects that POSTGRES_PASSWORD is still set to the placeholder value. It will still start — but you should treat this warning as urgent.
The database port is not published outside the Docker network by default, so the password primarily protects against container-to-container or volume-level compromise. Still, using the default placeholder is bad practice.
By default, the /admin dashboard and /workspace UI are enabled. For deployments where you want to expose only the API (e.g., behind an application that calls the API programmatically), you can disable the browser UIs:
In .env:
AGENT_API_DASHBOARD_ENABLED=false
AGENT_API_WORKSPACE_ENABLED=falseWhen set to false, those routes return HTTP 404. The underlying API endpoints (e.g., /api/jobs, /api/workspace/file) remain available.
Note: disabling the UI does not provide authentication — it only prevents the browser interface from loading. API endpoints are still unauthenticated. True protection requires either not publishing the port or using a reverse proxy with authentication.
The PUT /api/workspace/upload endpoint enforces a configurable maximum upload size. The default is 500 MB. Large uploads beyond this limit are rejected with HTTP 413.
To change the limit, set in .env:
AGENT_API_MAX_UPLOAD_BYTES=104857600 # 100 MBOr set agent.api.max_upload_bytes in config/agent.yaml.
The FastAPI interactive docs (/docs, /redoc) and the OpenAPI schema (/openapi.json) are disabled by default. They expose a full enumeration of all API endpoints and make it trivial for anyone with network access to discover the API surface.
To enable them for local development, set in .env:
AGENT_API_DOCS_ENABLED=true
AGENT_API_OPENAPI_ENABLED=trueDisable them again before connecting the server to any network you do not fully control.
GET /api/config/status returns the configured LLM model name, LLM base URL, admin email address, SMTP status, sandbox URL, embedding URL, and other operational parameters. This endpoint requires no authentication and is intentionally open on private deployments where it is useful for verifying your setup.
If the server is reachable from a network you do not fully control, be aware that this endpoint leaks configuration details to anyone who can reach it. The same network-level controls that protect the rest of the API apply here — see Network Binding and If You Must Expose This Publicly.
The sandbox service in docker-compose.yml mounts the Docker socket:
volumes:
- /var/run/docker.sock:/var/run/docker.sockWhy it's there: The sandbox broker creates fresh Docker containers to isolate each command execution. Mounting the socket is the mechanism by which the broker can spin up and tear down these ephemeral run containers. It is architecturally necessary for the container isolation mode.
The risk: A process inside the sandbox broker container that can write to the Docker socket has full control of the Docker daemon on the host — it can create privileged containers, mount host paths, etc. The sandbox broker is hardened (read-only filesystem, all capabilities dropped, no new privileges), but this is a high-privilege mount that you should be aware of.
Mitigations in place:
- The sandbox runs read-only with a
tmpfsat/tmp security_opt: no-new-privileges:trueis set- All Linux capabilities are dropped from the broker (
cap_drop: ALL) - The broker is on
sandbox_netonly — it cannot reachapp_netdirectly - Per-command run containers drop
NET_RAWand are resource-capped
If you want to eliminate the Docker socket exposure: Disable sandbox command execution entirely by setting agent.sandbox.enabled: false in config/agent.yaml. This removes the command_execute tool from the agent but everything else continues to work.
If you need to access the dashboard from outside your private network (e.g., from your phone over the internet), the recommended approach is:
Use nginx or Caddy in front of the agent with HTTP Basic Auth:
Nginx example:
server {
listen 443 ssl;
server_name assistant.yourdomain.com;
# TLS config here (certbot/Let's Encrypt)
# Password-protect everything
auth_basic "Assistant";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Generate the password file:
htpasswd -c /etc/nginx/.htpasswd yourusernameCaddy example:
assistant.yourdomain.com {
basicauth /* {
yourusername <hashed-password>
}
reverse_proxy 127.0.0.1:8000
}Keep AGENT_API_PUBLISHED_HOST=127.0.0.1 (or a LAN IP) and access remotely via WireGuard or Tailscale. This is the most secure option — the dashboard is never on the public internet.
If you have an application that calls specific API endpoints, proxy only those through nginx with auth, and keep the dashboard (/admin, /workspace) behind a separate, more restricted location block — or disable them entirely with AGENT_API_DASHBOARD_ENABLED=false.
- Reverse proxy with HTTPS and authentication in front of the stack
-
AGENT_API_PUBLISHED_HOST=127.0.0.1(proxy connects internally) -
AGENT_API_DOCS_ENABLEDandAGENT_API_OPENAPI_ENABLEDare not set totrue(they are off by default) -
POSTGRES_PASSWORDis a strong, unique password (not the placeholder) -
EMAIL_ACTIONABLE_SENDERSis locked down to only your address -
EMAIL_ALLOWED_RECIPIENT_DOMAINSis locked down to your domains - Consider
AGENT_API_DASHBOARD_ENABLED=falseandAGENT_API_WORKSPACE_ENABLED=falseif you don't need the browser UI from the public internet - Firewall rules block direct access to port 8000 from external IPs
If you discover a security vulnerability in this project, please open a GitHub issue or reach out privately before disclosing publicly. This is an open-source project without a formal security response team — issues will be addressed on a best-effort basis.