Reset database (deletes data):
docker compose down -v && docker compose up -d --buildIf the MySQL Docker volume already exists, changing MYSQL_* values in .env will not automatically update DB user passwords. The quickest fix is a full reset (deletes DB):
docker compose down -v && docker compose up -d --build- If you change
JWT_SECRET, all existing sessions/tokens become invalid. Clear site cookies (or hit/logout) and log in again. - If you change MySQL passwords (
MYSQL_*) on an existingmysql_datavolume, the container won’t automatically update the stored user credentials. Either update them in MySQL or reset the volume (see above).
Most common cause is cookie hardening mismatch:
- Accessing over plain HTTP (
http://localhost:8081): keepTAILSHELL_COOKIE_SECUREempty/false. - Accessing over HTTPS (e.g. Tailscale Serve URL): set
TAILSHELL_COOKIE_SECURE=true, then restart the stack.
Then clear cookies for the site (or hit /logout) and try again.
If ./scripts/... fails with Permission denied, run via bash:
bash ./scripts/generate-env
bash ./scripts/docker-setupCheck service status:
systemctl --user status ai-ttyd-docker
journalctl --user -u ai-ttyd-docker -eVerify ttyd is running:
ps aux | rg 'ttyd ' || true
# Should show: ttyd -i 0.0.0.0 -p 7681 -O -W -- ...The ttyd service runs under a user systemd unit. If that unit uses ProtectHome=read-only, only the web terminal becomes read-only.
Fix:
bash ./scripts/docker-setup
systemctl --user daemon-reload
systemctl --user restart ai-ttyd-dockerVerify the unit contains ProtectHome=no:
systemctl --user cat ai-ttyd-docker | rg ProtectHomeThe UI maps:
- Workspaces → tmux sessions
- Tabs → tmux windows
Useful commands:
tmux ls
tmux list-windows -t <session>
tmux kill-session -t <session>
tmux kill-window -t <session>:<window_index>If the UI seems out of sync, use Tools → Sync tabs or refresh the page. If you updated tmux helper scripts, run:
bash ./scripts/ui-deploy-
Verify Tailscale Serve is configured:
tailscale serve status
-
Ensure “Shields Up” is disabled:
tailscale set --shields-up=false
-
Verify the Docker stack is running:
docker compose ps curl http://127.0.0.1:8081/api/health
-
Verify Windows can reach nginx on localhost:
curl http://localhost:8081/
If this fails, enable WSL localhost forwarding in
%UserProfile%\.wslconfig:[wsl2] localhostForwarding=true
Then run:
wsl --shutdown
- Hard refresh:
Ctrl+Shift+R - Assets under
/assets/are hashed and cached long-term; if you redeploy, you should see new hashes inindex.html.
If the browser keeps showing the old UI even after a rebuild, verify that Docker actually owns 127.0.0.1:8081.
Check who is listening:
sudo ss -ltnp 'sport = :8081'
sudo lsof -iTCP:8081 -sTCP:LISTEN -PnIf you see docker-proxy pointing to a container IP that no longer exists, it can be a stale Docker network. Find the network subnet and remove it:
docker network inspect $(docker network ls -q) --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}'
docker network inspect <network-name> --format '{{json .Containers}}'
docker network rm <network-name>If the proxy remains, restart Docker (this restarts containers):
sudo service docker restartThen rebuild nginx and hard refresh the browser:
UI_CACHEBUST=$(date +%s) docker compose up -d --build nginx