feat: add support for custom URL paths via BASE_URL configuration
Summary
Fixes #1156 and #1323
This PR adds support for deploying Planka under custom URL paths by extracting the path from the BASE_URL environment variable and injecting it into the client at runtime.
Problem
Previously, Planka could only be deployed at the root path (/). Users wanting to deploy it under a subpath (e.g., /planka) behind a reverse proxy had to rebuild the Docker image with build-time environment variables, which is not feasible for users pulling pre-built images.
Solution
Architecture Changes
-
Runtime Configuration Injection
- Created a bash script (
inject-config-template.sh) that converts the Vite-builtindex.htmlinto an EJS template - Added a new controller (
index/show) that injectsbaseUrlPathfrom server config into the template - Client reads configuration from
window.PLANKA_CONFIGat runtime
- Created a bash script (
-
Path Handling
- Replaced build-time
SERVER_BASE_URLwith runtimeBASE_PATHthroughout the client - Updated all route definitions (
Paths.js) to use the dynamic base path - Modified API and WebSocket paths to include the base path prefix
- Replaced build-time
-
Cookie Path Fix
- Fixed authentication cookie paths to handle both root (
/) and subpath deployments - Added fallback to
'/'whenbaseUrlPathis empty to ensure valid cookie paths - Applied fix to both server-side (
httpOnlyToken) and client-side (accessToken) cookies
- Fixed authentication cookie paths to handle both root (
Technical Details
Server changes:
-
server/config/custom.js: Extract and strip trailing slash fromBASE_URLpathname -
server/inject-config-template.sh: AWK script to inject EJS template into HTML (new file) -
server/api/controllers/index/show.js: Controller that passesbaseUrlPathto the view (new file) -
server/config/routes.js: Changedindexfrom direct view rendering to controller action -
server/config/views.js: Changed extension from.htmlto.ejs -
server/config/policies.js: Added public access policy forindex/showcontroller -
server/api/helpers/utils/set-http-only-token-cookie.js: Added|| '/'fallback for cookie path
Client changes:
-
client/src/constants/Config.js: ReadBASE_PATHfromwindow.PLANKA_CONFIG.baseUrlPathat runtime -
client/src/constants/Paths.js: PrependBASE_PATHto all route definitions -
client/src/api/http.js: UseBASE_PATHinstead ofSERVER_BASE_URLfor API calls -
client/src/api/socket.js: ConfigureSocket.IOpath withBASE_PATHprefix -
client/src/utils/access-token-storage.js: Set proper cookie paths with fallback to'/' -
client/vite.config.js: Setbase: './'for relative asset paths
Build changes:
-
Dockerfile: Transformindex.htmltoindex.ejstemplate during image build
Testing
Tested with the following nginx configuration:
server {
listen 80;
server_name localhost;
location /planka/ {
rewrite ^/planka(.*)$ $1 break;
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Prefix /planka;
}
}
And this BASE_URL environment variable in docker-compose.yml:
environment:
- BASE_URL=http://localhost/planka # or any custom path
Breaking Changes
None. Existing deployments at root path continue to work without any configuration changes.
Additional note
This is my first contribution to the project. If something is wrong, missing or anyone has a better idea to implement this, please let me know and I'll adapt my changes to your needs.
Hey! Thanks for your PR 🙏 I'll definitely check and test it soon. We're in the middle of preparing the final v2 release, so it might take a bit of time to get to everything.