feat: add external_url config for reverse proxy deployments#1584
Open
ianbmacdonald wants to merge 5 commits intolemonade-sdk:mainfrom
Open
feat: add external_url config for reverse proxy deployments#1584ianbmacdonald wants to merge 5 commits intolemonade-sdk:mainfrom
ianbmacdonald wants to merge 5 commits intolemonade-sdk:mainfrom
Conversation
Collaborator
Author
Collaborator
Author
|
add @sofiageo's comment |
Geramy
reviewed
Apr 8, 2026
Member
Geramy
left a comment
There was a problem hiding this comment.
I like it generally. Please see changes.
Collaborator
Author
Collaborator
Author
Testing this branchPrerequisites
Quick test with Caddy1. Configure lemonade: lemonade config set \
external_url=https://<YOUR_IP>:8443 \
host=127.0.0.1 \
websocket_port=9000
2. Install and configure Caddy: sudo apt install caddy
sudo systemctl restart caddy3. Verify: Open
4. Cleanup (to restore default behavior): lemonade config set external_url= host=0.0.0.0 websocket_port=auto
sudo systemctl stop caddyWhat to look for
|
Adds an `external_url` server config key that lets users specify the public-facing URL when Lemonade runs behind a reverse proxy. When set, the web app and WebSocket clients derive all browser-facing URLs from it instead of using internal hostnames and ports. - external_url config key with http/https validation in runtime_config - Server injects external_url into web app mock API for frontend use - Frontend prefers external_url > window.location.origin > localhost - WebSocket clients use base URL origin (no separate port) when external_url is set, fixing mixed-content and port exposure issues - Direct-connect mode gains ws:// vs wss:// protocol detection Fixes lemonade-sdk#472 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The hasExternalUrl flag was set for any explicit base URL, including Electron's --base-url. This caused Electron/remote-server setups to stop using the advertised websocket_port and assume /realtime and /logs/stream exist on the HTTP origin — a regression for users without a same-origin WS proxy. Now hasExternalUrl is only true in web-app mode (server-injected external_url), where the reverse proxy is expected to forward WS paths. Electron --base-url continues using the separate websocket_port. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Escape external_url via JSON serialization instead of raw string concatenation in the injected <script> tag (server.cpp) - Validate external_url with a regex rejecting query/fragment (runtime_config.cpp) - Extract getWebSocketUrl() helper in serverConfig.ts so both WS clients share a single URL-construction path that handles path prefixes correctly (e.g. https://example.com/lemonade/realtime) - Add log_external_url_proxy_warning() emitted at startup and on config change when external_url is set but websocket_port is auto - Handle external_url as a runtime-changeable config key in apply_config_side_effects - Document reverse proxy deployment contract in configuration.md and update WebSocket connection docs in server_spec.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove standalone getWebSocketProtocol export — the protocol logic is only used inside getWebSocketUrl, so keep it there. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The serve_web_app_html lambda only needs RuntimeConfig, not the entire Server object. Capture config_.get() directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8a1891f to
0abf920
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
external_urlserver config key for specifying the public browser-facing URL when Lemonade runs behind a reverse proxyexternal_urlinstead of internal hostnames and portswss://example.com/realtime) rather than connecting directly to:9000isExternalUrl()is scoped to web-app mode onlyws://vswss://protocol detection for direct-connect modeexternal_urlis set butwebsocket_portis still"auto"Full context in #472 (comment).
Changes
defaults.jsonexternal_url: ""runtime_config.h/.cppserver.cppexternal_urlvia JSON-serialized<script>tag; proxy misconfiguration warning; side-effect handlingserverConfig.tsexternal_url>window.location.origin>localhost;getWebSocketUrl()helper;isExternalUrl()scoped to web-app modewebsocketClient.ts/logWebSocketClient.tsgetWebSocketUrl()configuration.mdexternal_url, reverse proxy section with nginx exampleserver_spec.mdDeployment
lemonade config set external_url=https://lemonade.example.com websocket_port=9000Test plan
external_urlset — verify local, Electron, and direct-connect modes work exactly as beforeexternal_url=http://localhost:13305— web app should use that as base URL, WS connects via originexternal_url=https://example.combehind HTTPS proxy — REST useshttps://, WS useswss://, no mixed-content errorsexternal_url=https://example.com/lemonadewith path prefix — verify/lemonade/realtimeand/lemonade/logs/streampathsexternal_urlwithwebsocket_port=auto— verify startup warning is loggedlemonade config set external_url=...at runtime — verify side-effect log message and warning re-check--base-url— verify it still useswebsocket_portfrom/health(no regression)Fixes #472
🤖 Generated with Claude Code