Skip to content

Fix reverse proxy subpath support using External_Webserver_address#4513

Draft
Leolebleis wants to merge 2 commits intoplan-player-analytics:masterfrom
Leolebleis:fix/external-address-reverse-proxy-subpath
Draft

Fix reverse proxy subpath support using External_Webserver_address#4513
Leolebleis wants to merge 2 commits intoplan-player-analytics:masterfrom
Leolebleis:fix/external-address-reverse-proxy-subpath

Conversation

@Leolebleis
Copy link
Contributor

Your checklist for this pull request

  • Make sure your name is added to Contributors file /Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/html/Contributors.java
  • No locale changes

Description

When Plan runs behind a reverse proxy at a subpath (e.g. /minecraft/stats/), External_Webserver_address was only consulted when the webserver was disabled. With the webserver running, both HTML asset paths and PLAN_BASE_ADDRESS used the internal address (e.g. http://localhost:8804), breaking static asset loading, React Router navigation, and API calls (wrong protocol/path).

Changes:

  • Addresses.getExternalAddress() — new method returning External_Webserver_address when set to a non-default value
  • BundleAddressCorrection.getWebserverBasePath() — prefers external address base path for HTML/JS/CSS path rewriting
  • ResponseFactory.replaceMainAddressPlaceholder() — prefers external address for PLAN_BASE_ADDRESS injection

Tested on a live deployment (Plan v5.7 b3288 behind nginx HTTPS proxy at a subpath). Unit tests included.

When Plan runs behind a reverse proxy at a subpath (e.g. /minecraft/stats/),
the External_Webserver_address config was only used as a fallback when the
webserver was disabled. This meant HTML asset paths stayed root-relative
(/static/...) and PLAN_BASE_ADDRESS was injected with the internal address,
breaking both static asset loading and React Router navigation.

Add Addresses.getExternalAddress() that returns the configured external
address when valid, and prefer it in both BundleAddressCorrection (for
HTML/JS/CSS path rewriting) and ResponseFactory (for PLAN_BASE_ADDRESS
injection). This gives the JS the correct protocol and subpath for
reverse proxy setups.
The Vite __vitePreload helper uses `return"/"+l` to construct asset
URLs. When deployed at a subpath, this produces root-relative paths
like `/static/...` instead of `/plan/static/...`, causing CSS preload
failures.

Replace the hardcoded "/" prefix with the base path when configured.
@Leolebleis Leolebleis marked this pull request as draft March 15, 2026 13:47
@AuroraLS3
Copy link
Collaborator

Alternative_IP.Address is used for this purpose - External address is intended for use when Export is being used

@Leolebleis
Copy link
Contributor Author

Alternative_IP.Address is used for this purpose - External address is intended for use when Export is being used

@AuroraLS3 Ah I see, thanks! I originally tried Alternative_IP but ran into two issues with HTTPS reverse proxy setups:

  1. Mixed content: Alternative_IP gets prepended with Plan's webserver protocol (http://), so PLAN_BASE_ADDRESS becomes http://example.com/plan. On an HTTPS page, API calls to http://... are blocked as mixed content by browsers.
  2. getMainAddress() checks DB first: BundleAddressCorrection.getWebserverBasePath() uses getMainAddress(), which queries plan_servers before checking getAccessAddress(). The DB stores the internal address (http://localhost:8804), so Alternative_IP never affects path correction.

External_Webserver_address avoids both issues since it includes the correct protocol (https://) and isn't overridden by the DB lookup.

Would you prefer a different approach — e.g. making Alternative_IP protocol-aware, or having getMainAddress() also consider Alternative_IP?

@AuroraLS3
Copy link
Collaborator

When using reverse-proxy based https you can set up Plan to assume https with proxy-mode: https://github.com/plan-player-analytics/Plan/wiki/SSL-Certificate-%28HTTPS%29-Set-Up#if-behind-a-proxy

@AuroraLS3
Copy link
Collaborator

@Leolebleis
Copy link
Contributor Author

Ah ok thank you :) I need to AFK for a bit but will check later, I think I tried that and ran into issues

Will get back to you asap!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants