documentation/docs/guides/remote-goose-server.md
goose Desktop normally runs its own goosed server process in the background on the same machine. You can also run goosed 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:
goosed server on a remote machinegoosed as a background service on macOS:::warning TLS is required
goose Desktop will refuse to connect to a remote goosed server over plain HTTP. TLS is enabled by default (GOOSE_TLS=true), so make sure you have not disabled it.
:::
goosed serverOn the remote machine, launch goosed with the host, port, TLS, and a shared secret key:
GOOSE_HOST=0.0.0.0 \
GOOSE_PORT=3000 \
GOOSE_TLS=true \
GOOSE_SERVER__SECRET_KEY='YOUR_SECRET' \
/Applications/Goose.app/Contents/Resources/bin/goosed agent
On Linux or Windows the path to the goosed binary will differ — use the one bundled with your goose installation, or a standalone goosed build.
| Variable | Purpose |
|---|---|
GOOSE_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. |
GOOSE_PORT | TCP port to listen on. |
GOOSE_TLS | Must be true. goose Desktop will not connect to a plain HTTP server. |
GOOSE_SERVER__SECRET_KEY | Shared secret. The client must send this in the X-Secret-Key header. Treat it like a password. |
:::tip
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.
:::
First, confirm goosed is actually listening on the port you expect:
lsof -nP -iTCP:3000 -sTCP:LISTEN
Then test the endpoints from the server itself. The -k flag tells curl to accept the self-signed TLS certificate that goosed generates:
# Connectivity only
curl -i https://127.0.0.1:3000/status -k
# Authenticated endpoint (real test)
curl -i https://127.0.0.1:3000/config/read -k \
-H 'Content-Type: application/json' \
-H 'X-Secret-Key: YOUR_SECRET' \
--data '{"key":"GOOSE_PROVIDER","is_secret":false}'
A 200 response from the second call confirms that TLS is up, the secret key is being accepted, and the server is ready to receive client requests.
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.
Because goosed generates a self-signed TLS certificate, goose Desktop pins it by SHA-256 fingerprint rather than relying on a public certificate authority.
When TLS is enabled, goosed logs the fingerprint on startup. It looks like:
GOOSED_CERT_FINGERPRINT=AA:BB:CC:DD:EE:FF:...
To capture it, either:
goosed interactively and read it from the terminal output, orgoosed as a background service):grep GOOSED_CERT_FINGERPRINT ~/Library/Logs/GooseExternal/goosed.out.log
Make a note of the fingerprint — you will paste it into goose Desktop in the next step.
:::note
The fingerprint changes whenever goosed 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.
:::
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 | The GOOSED_CERT_FINGERPRINT value from the server logs |
After saving, goose Desktop will route all backend requests to the remote goosed. If the connection fails, see Troubleshooting.
goosed as a Background Service (macOS)Running goosed 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.goosed.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.goosed.external</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Goose.app/Contents/Resources/bin/goosed</string>
<string>agent</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>GOOSE_HOST</key><string>0.0.0.0</string>
<key>GOOSE_PORT</key><string>3000</string>
<key>GOOSE_TLS</key><string>true</string>
<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/goosed.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USERNAME/Library/Logs/GooseExternal/goosed.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.goosed.external.plist
launchctl kickstart -k gui/$(id -u)/com.goose.goosed.external
To stop or remove it later:
launchctl bootout gui/$(id -u)/com.goose.goosed.external
:::tip
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.goosed.external.plist.
:::
If curl works from the server but the client machine times out or gets "connection refused", check what interface goosed is bound to. If GOOSE_HOST is localhost or 127.0.0.1, only loopback connections are accepted.
Set GOOSE_HOST=0.0.0.0 to accept connections on all interfaces, then restart goosed. 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.
In the server's startup logs:
listening on http://..., TLS is not enabled. goose Desktop will not connect. Set GOOSE_TLS=true and restart goosed.listening on https://..., TLS is enabled and you are good to go.The startup logs also contain the GOOSED_CERT_FINGERPRINT=... line you need for the goose Desktop configuration. Search the server's stdout (or log file, if running under launchd) for GOOSED_CERT_FINGERPRINT to find it.
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. If that returns 200, the secret is correct and the problem is in the client configuration; if it returns 401, 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.
If goose Desktop refuses to connect with a certificate or fingerprint error, the most common causes are:
GOOSED_CERT_FINGERPRINT and update goose Desktop.GOOSE_* variables