Repository navigation
Native and Kubernetes Deployment
This guide covers persistent background deployment of chat-export-server across macOS, Linux, Windows, Docker / Colima, and Kubernetes (deploy/k8s), while keeping the local-first loopback security model (127.0.0.1:8765).
Browser automation is performed by the Chat Export Chrome extension (WebSocket ceb_ bridge into your logged-in tabs). You do not need Chrome DevTools MCP, Playwright, or an IDE-attached debugger for normal operation.
Install Node.js 22+ via Homebrew and build the server:
brew install node@22
git clone https://github.com/svergio/chat-export-server.git
cd chat-export-server
npm install && npm run buildCreate the server home directory and .env file:
mkdir -p ~/.chat-export
chmod 700 ~/.chat-export
cat > ~/.chat-export/.env <<'EOF'
CHAT_EXPORT_HOME=/Users/YOUR_USER/.chat-export
CHAT_EXPORT_HOST=127.0.0.1
CHAT_EXPORT_PORT=8765
CHAT_EXPORT_DASHBOARD_ENABLED=true
CHAT_EXPORT_ADMIN_USER=admin
CHAT_EXPORT_ADMIN_PASS=change_this_password
CHAT_EXPORT_MCP_TOKEN=cem_YOUR_GENERATED_TOKEN
CHAT_EXPORT_ALLOW_DESTRUCTIVE=false
EOF
chmod 600 ~/.chat-export/.envGenerate a fresh MCP key with node dist/cli.js key new if you prefer hash-only storage in ~/.chat-export/keys.json.
Create the LaunchAgent plist so chat-export-server starts automatically at login and restarts on failure:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>io.github.svergio.chat-export-server</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/node</string>
<string>/ABS/PATH/TO/chat-export-server/dist/cli.js</string>
<string>start</string>
</array>
<key>WorkingDirectory</key>
<string>/ABS/PATH/TO/chat-export-server</string>
<key>EnvironmentVariables</key>
<dict>
<key>CHAT_EXPORT_HOME</key>
<string>/Users/YOUR_USER/.chat-export</string>
<key>CHAT_EXPORT_ENV_FILE</key>
<string>/Users/YOUR_USER/.chat-export/.env</string>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/YOUR_USER/.chat-export/server.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USER/.chat-export/server.log</string>
</dict>
</plist>Load and manage the service:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/io.github.svergio.chat-export-server.plist
launchctl kickstart -k gui/$(id -u)/io.github.svergio.chat-export-server
tail -f ~/.chat-export/server.log
curl -sS http://127.0.0.1:8765/healthInstall Node.js 22+ (via NodeSource, fnm, or nvm) and build chat-export-server:
git clone https://github.com/svergio/chat-export-server.git ~/chat-export-server
cd ~/chat-export-server
npm install && npm run build
mkdir -p ~/.chat-export ~/.config/systemd/user
cp .env.example ~/.chat-export/.env
chmod 600 ~/.chat-export/.env[Unit]
Description=Chat Export MCP and Browser Bridge Server
After=network.target
[Service]
Type=simple
WorkingDirectory=%h/chat-export-server
Environment=CHAT_EXPORT_HOME=%h/.chat-export
EnvironmentFile=%h/.chat-export/.env
ExecStart=/usr/bin/env node %h/chat-export-server/dist/cli.js start
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.targetEnable lingering (so the user service runs even before GUI login) and start the unit:
systemctl --user daemon-reload
systemctl --user enable --now chat-export-server
loginctl enable-linger "$USER"
journalctl --user -u chat-export-server -fInstall Node.js 22+ via winget or nvm-windows:
winget install OpenJS.NodeJS.LTS
git clone https://github.com/svergio/chat-export-server.git "$env:USERPROFILE\chat-export-server"
Set-Location "$env:USERPROFILE\chat-export-server"
npm install
npm run build
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.chat-export" | Out-Null
Copy-Item .env.example "$env:USERPROFILE\.chat-export\.env"Edit $env:USERPROFILE\.chat-export\.env and set CHAT_EXPORT_HOST=127.0.0.1, CHAT_EXPORT_PORT=8765, and CHAT_EXPORT_ADMIN_PASS.
Register a background logon task bound to 127.0.0.1:8765:
$NodePath = (Get-Command node).Source
$ServerDir = "$env:USERPROFILE\chat-export-server"
$EnvFile = "$env:USERPROFILE\.chat-export\.env"
$Action = New-ScheduledTaskAction `
-Execute $NodePath `
-Argument "`"$ServerDir\dist\cli.js`" start" `
-WorkingDirectory $ServerDir
$Trigger = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME
$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
[System.Environment]::SetEnvironmentVariable("CHAT_EXPORT_HOME", "$env:USERPROFILE\.chat-export", "User")
[System.Environment]::SetEnvironmentVariable("CHAT_EXPORT_ENV_FILE", $EnvFile, "User")
Register-ScheduledTask -TaskName "ChatExportServer" -Action $Action -Trigger $Trigger -Settings $Settings -Force
Start-ScheduledTask -TaskName "ChatExportServer"Equivalent schtasks CLI registration:
schtasks /Create /TN "ChatExportServer" /TR "`"C:\Program Files\nodejs\node.exe`" `"$env:USERPROFILE\chat-export-server\dist\cli.js`" start" /SC ONLOGON /RL LIMITED /F
schtasks /Run /TN "ChatExportServer"With NSSM (Non-Sucking Service Manager):
nssm install ChatExportServer "C:\Program Files\nodejs\node.exe" "`"$env:USERPROFILE\chat-export-server\dist\cli.js`" start"
nssm set ChatExportServer AppDirectory "$env:USERPROFILE\chat-export-server"
nssm set ChatExportServer AppEnvironmentExtra "CHAT_EXPORT_HOME=$env:USERPROFILE\.chat-export" "CHAT_EXPORT_ENV_FILE=$env:USERPROFILE\.chat-export\.env"
nssm start ChatExportServerWith PM2:
npm install -g pm2
$env:CHAT_EXPORT_HOME="$env:USERPROFILE\.chat-export"
$env:CHAT_EXPORT_ENV_FILE="$env:USERPROFILE\.chat-export\.env"
pm2 start "$env:USERPROFILE\chat-export-server\dist\cli.js" --name chat-export-server -- start
pm2 saveOn macOS, Colima provides a lightweight runtime without Docker Desktop:
colima start
docker context use colima
cd chat-export-server
cp .env.example .env # set CHAT_EXPORT_ADMIN_PASS and tokens
docker compose build
docker compose up -d
curl -sS http://127.0.0.1:8765/healthThe container binds 127.0.0.1:8765:8765 on the host and persists state in the chat-export-data named volume mounted at /data.
When running the workspace root docker-compose.yml alongside chat-export-dashboard:
-
serverrunschat-export-server:localinternally on port8765with/datamounted onchat-export-data. -
webrunschat-export-dashboard:local(nginx) published at127.0.0.1:8765:80, serving dashboard static assets and reverse-proxying/mcp,/ws,/api, and/healthtoSERVER_UPSTREAM=server:8765.
docker compose build
docker compose up -d
curl -sS http://127.0.0.1:8765/healthFor self-hosted clusters (k3s, kind, Colima Kubernetes, MicroK8s, or cloud clusters), deploy/k8s packages a Kustomize overlay with a StatefulSet/Deployment, PersistentVolumeClaim, Secret, and ClusterIP service.
Populate your secrets before applying (never commit plaintext tokens to git):
kubectl create namespace chat-export --dry-run=client -o yaml | kubectl apply -f -
kubectl -n chat-export create secret generic chat-export-secrets \
--from-literal=CHAT_EXPORT_ADMIN_USER=admin \
--from-literal=CHAT_EXPORT_ADMIN_PASS='YOUR_STRONG_ADMIN_PASSWORD' \
--from-literal=CHAT_EXPORT_MCP_TOKEN='cem_YOUR_MCP_TOKEN' \
--from-literal=CHAT_EXPORT_BROWSER_TOKENS='b-main:ceb_YOUR_BROWSER_TOKEN:Chrome Main' \
--dry-run=client -o yaml | kubectl apply -f -kubectl apply -k deploy/k8s
kubectl -n chat-export rollout status deploy/chat-export-server
kubectl -n chat-export get pvc,pods,svcThe PVC mounts at /data (CHAT_EXPORT_HOME=/data), preserving config.json, keys.json, SQLite cache (chat-export.db), exports/, and audit.log across pod restarts.
Do not expose chat-export-server on a public unauthenticated Ingress. Instead, forward the service to local loopback on the workstation running Chrome and your MCP client:
kubectl -n chat-export port-forward --address 127.0.0.1 svc/chat-export-server 8765:8765With kubectl port-forward active on 127.0.0.1:8765:
- Open the Chrome extension popup → Advanced → set host
127.0.0.1, port8765, and paste theceb_…token fromchat-export-secrets(or enroll viahttp://127.0.0.1:8765/dashboard/). - Enable Server bridge (
ws://127.0.0.1:8765/wstunnels over the K8s port-forward directly into the pod). - Point any MCP client (Cursor, Claude Desktop, local LLM agent, etc.) to
http://127.0.0.1:8765/mcpwithAuthorization: Bearer cem_….