Running a Remote goose Server
goose Desktop normally runs its own goose serve ACP server process in the background on the same machine. You can also run goose serve separately — for example, on a remote VM or a different machine on your network — and point goose Desktop at it.
This is useful when you want goose to run somewhere with more compute, a stable IP, or shared access, while still driving it from a local Desktop UI.
This guide covers:
- Starting a
goose serveserver on a remote machine - Verifying it is reachable
- Locating the certificate fingerprint
- Configuring goose Desktop to connect to it
- Running
goose serveas a background service on macOS - Troubleshooting
goose Desktop accepts both HTTP and HTTPS external backend URLs, but TLS is strongly recommended when connecting over a network. Certificate fingerprint pinning requires HTTPS.
Initial Setup
1. Start the goose serve server
On the remote machine, launch goose serve with the host, port, TLS, and a shared secret key:
GOOSE_SERVER__SECRET_KEY='YOUR_SECRET' \
goose serve --platform desktop --host 0.0.0.0 --port 3000 --tls
If you are using the binary bundled with the macOS app, the command path is /Applications/Goose.app/Contents/Resources/bin/goose.
| Setting | Purpose |
|---|---|
--host | Interface to bind to. Use 0.0.0.0 to accept connections from other machines. Binding to localhost or 127.0.0.1 will only accept local connections. |
--port | TCP port to listen on. |
--tls / GOOSE_TLS=true | Enables TLS. Strongly recommended for remote servers and required for certificate fingerprint pinning. |
GOOSE_SERVER__SECRET_KEY | Shared secret. The client must send this to the ACP endpoint. Treat it like a password. |
Pick a long, random value for GOOSE_SERVER__SECRET_KEY and store it in a password manager — the same value goes into goose Desktop later.
2. Verify the server is up
First, confirm goose serve is actually listening on the port you expect:
lsof -nP -iTCP:3000 -sTCP:LISTEN
Then test the server from the server itself. The -k flag tells curl to accept the self-signed TLS certificate that goose serve generates:
# Connectivity only
curl -i https://127.0.0.1:3000/status -k
# ACP endpoint auth check. A 401 means the secret was rejected.
curl -i https://127.0.0.1:3000/acp -k \
-H 'X-Secret-Key: YOUR_SECRET'
A successful /status response confirms that TLS is up. The /acp check should not return 401 when the secret is correct.
If you intend to reach the server from another machine, also test from there using the server's hostname or VPN address — not 127.0.0.1.
3. Optionally find the certificate fingerprint
When goose serve runs with TLS, it generates or loads a TLS certificate. goose Desktop can pin that certificate by SHA-256 fingerprint. If you leave the fingerprint field empty, goose Desktop uses trust-on-first-use and pins the first certificate it sees for that backend.
When TLS is enabled, goose serve logs the fingerprint on startup. It looks like:
GOOSED_CERT_FINGERPRINT=AA:BB:CC:DD:EE:FF:...
To capture it, either:
- Run
goose serveinteractively and read it from the terminal output, or - Tail the log file you redirect to when running as a service (see Running
goose serveas a background service):
grep GOOSED_CERT_FINGERPRINT ~/Library/Logs/GooseExternal/goose-serve.out.log
Make a note of the fingerprint if you want to pin a specific certificate in goose Desktop.
The fingerprint changes whenever goose serve regenerates its certificate (for example, if you delete the cert file). If goose Desktop suddenly refuses to connect after a server restart, re-check the fingerprint.
4. Configure goose Desktop
On the client machine, open goose Desktop and navigate to Settings → goose Server:
| Setting | Value |
|---|---|
| Use external server | Enabled |
| URL | https://your-server-host:3000 (use the hostname or IP that the client can reach — for example a VPN/tailnet address) |
| Secret Key | The same value you used for GOOSE_SERVER__SECRET_KEY |
| Certificate Fingerprint | Optional. Use the GOOSED_CERT_FINGERPRINT value from the server logs to pin a specific TLS certificate. |
After saving, goose Desktop will route all backend requests to the remote goose serve process. If the connection fails, see Troubleshooting.
Running goose serve as a Background Service (macOS)
Running goose serve in a terminal session is fine for testing, but for everyday use you probably want it managed as a background service so it starts at login and restarts on failure. On macOS, this is done with launchd.
Create a LaunchAgent plist at ~/Library/LaunchAgents/com.goose.serve.external.plist:
<?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>com.goose.serve.external</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Goose.app/Contents/Resources/bin/goose</string>
<string>serve</string>
<string>--platform</string>
<string>desktop</string>
<string>--host</string>
<string>0.0.0.0</string>
<string>--port</string>
<string>3000</string>
<string>--tls</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>GOOSE_SERVER__SECRET_KEY</key><string>YOUR_SECRET</string>
</dict>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key>
<string>/Users/YOUR_USERNAME/Library/Logs/GooseExternal/goose-serve.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USERNAME/Library/Logs/GooseExternal/goose-serve.err.log</string>
</dict>
</plist>
Replace YOUR_SECRET and YOUR_USERNAME with appropriate values, and make sure the log directory exists:
mkdir -p ~/Library/Logs/GooseExternal
Then load and start the service:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.goose.serve.external.plist
launchctl kickstart -k gui/$(id -u)/com.goose.serve.external
To stop or remove it later:
launchctl bootout gui/$(id -u)/com.goose.serve.external
Because the secret key is stored in plain text in the plist, the file should be readable only by your user. macOS LaunchAgents under ~/Library/LaunchAgents/ are already user-scoped, but you can tighten further with chmod 600 ~/Library/LaunchAgents/com.goose.serve.external.plist.
Troubleshooting
Server only accepts local connections
If curl works from the server but the client machine times out or gets "connection refused", check what interface goose serve is bound to. If --host is localhost or 127.0.0.1, only loopback connections are accepted.
Set --host 0.0.0.0 to accept connections on all interfaces, then restart goose serve. You can verify with:
lsof -nP -iTCP:3000 -sTCP:LISTEN
The output should show the address as *:3000 or the specific external IP, not 127.0.0.1:3000.
TLS is not enabled
In the server's startup logs:
- If you see
listening on http://..., TLS is not enabled. goose Desktop can still connect over HTTP, but this is not recommended for remote servers. Start with--tlsorGOOSE_TLS=trueand restartgoose serve. - If you see
listening on https://..., TLS is enabled and you are good to go.
The startup logs also contain the GOOSED_CERT_FINGERPRINT=... line you can use for certificate pinning in goose Desktop. Search the server's stdout (or log file, if running under launchd) for GOOSED_CERT_FINGERPRINT to find it.
Client cannot authenticate (401 / Unauthorized)
A 401 from the server, or a goose Desktop error indicating that the secret was rejected, almost always means that GOOSE_SERVER__SECRET_KEY on the server does not match the Secret Key in goose Desktop's settings.
To check the secret end-to-end without involving goose Desktop, run the authenticated curl from step 2 using exactly the value you have configured on the client. For this GET /acp probe, a 406 response means authentication passed but the request did not include the SSE headers needed by the ACP stream. A 401 or 403 means the secret on the server is different from what you are sending.
If you rotate the secret on the server, you must also update it in goose Desktop's settings — they are not synchronized automatically.
Certificate fingerprint mismatch
If goose Desktop refuses to connect with a certificate or fingerprint error, the most common causes are:
- The server regenerated its certificate (for example, after deleting the cert file). Look at the latest startup logs for the current
GOOSED_CERT_FINGERPRINTand update goose Desktop. - You copied the fingerprint with extra whitespace or pasted the wrong value.
Related
- Environment Variables — full reference for all
GOOSE_*variables - Configuration Files — persistent client-side configuration