Skip to content

fix(cli,ui): add consistent basePath handling for subpath deployments (N8N_PATH) - #19638

Open
skyplane23 wants to merge 28 commits into
n8n-io:masterfrom
skyplane23:issue/subpath-basepath-inconsistencies
Open

fix(cli,ui): add consistent basePath handling for subpath deployments (N8N_PATH)#19638
skyplane23 wants to merge 28 commits into
n8n-io:masterfrom
skyplane23:issue/subpath-basepath-inconsistencies

Conversation

@skyplane23

@skyplane23 skyplane23 commented Sep 17, 2025

Copy link
Copy Markdown

Summary

This PR adds first-class subpath support by consistently honoring N8N_PATH (aka basePath) across the backend and frontend. It fixes the long-standing issue where n8n appears to work only with reverse-proxy rewrites (stripping the subpath) and breaks features that depend on exact URLs.

What changed

Backend (CLI/server):

  • Introduce and normalize basePath in AbstractServer and propagate it everywhere routes are registered.
    • Normalize (strip trailing /, ensure leading /) and reuse for all mounts.
  • Serve static editor UI and assets under basePath:
    • this.app.use('${basePath}/', historyApiHandler, express.static(...))
    • Icon endpoints now resolve using basePath (resolveIcon(basePath, packageName, req.originalUrl)).
  • REST/schema and internal routes now include basePath:
    • /${basePath}/${restEndpoint}/schemas/:node/:version/:resource/:operation.json
    • Health checks moved to ${basePath}/healthz and ${basePath}/healthz/readiness.
  • Webhook-related mounts now include basePath:
    • Live forms: ${basePath}/${endpointForm}/*path
    • Live webhooks: ${basePath}/${endpointWebhook}/*path
    • Waiting forms/webhooks: ${basePath}/${endpointFormWaiting}, ${basePath}/${endpointWebhookWaiting}
    • MCP and MCP test: ${basePath}/${endpointMcp}/*path, ${basePath}/${endpointMcpTest}/*path
    • Test webhook DELETE: ${basePath}/${restEndpoint}/test-webhook/:id
  • Push/SSE/WebSocket paths include basePath:
    • Server-sent events / push: ${basePath}/${restEndpoint}/push
    • WS upgrade check: pathname.includes(\/${restEndpoint}/push`)withbasePath` awareness.
  • Controller registry prefixes API routers with basePath (and normalizes it) instead of hardcoding root /.
  • Auth service:
    • Add an additional skip-list check using .some(skipEndpoint => endpoint.includes(skipEndpoint)) for robustness with basePath.
    • (OAuth callback list unchanged; still addressed by restEndpoint.)

Frontend (editor-ui):

  • Fix authenticated redirect to avoid dropping the subpath:
    • Use window.BASE_PATH when building the fallback redirect.
      const redirect = to.query.redirect ?? encodeURIComponent(\${url.pathname.replace(new RegExp(`^${window.BASE_PATH}`), '/')}${url.search}`);`

Key effect: All UI, API, push, schema, health, icons, and webhook endpoints are now mounted relative to N8N_PATH. Reverse-proxy rewrite hacks are no longer required for subpath deployments.

Why

When n8n is hosted at /my-n8n, many routes ignored N8N_PATH. Users could mask this via proxy rewrites, but Human-in-the-Loop (HITL) and other URL-sensitive features would fail because the browser used a subpath URL while the server verified against a rewritten (root) URL. Centralizing basePath and applying it consistently prevents these mismatches.


How to test

  1. Environment

    N8N_PATH=/my-n8n/
    N8N_EDITOR_BASE_URL=http://localhost:5678/my-n8n/
    WEBHOOK_URL=http://localhost:5678/my-n8n
  2. Start n8n without any reverse-proxy path rewrites (no stripping /my-n8n).

  3. Editor UI

    • Navigate to http://localhost:5678/my-n8n/
    • Confirm navigation/refresh and login redirects keep /my-n8n.
  4. Static assets & icons

    • Check node/credential icons load from ${basePath}/icons/....
  5. Health endpoints

    • GET http://localhost:5678/my-n8n/healthz{ status: "ok" }
    • GET http://localhost:5678/my-n8n/healthz/readiness → 200 once DB ready.
  6. REST & schemas

    • Schema JSON under ${basePath}/${restEndpoint}/schemas/... resolves.
  7. Push/SSE/WS

    • Open editor; network tab should show EventSource/WS to ${basePath}/${restEndpoint}/push.
  8. Webhooks & forms (incl. HITL)

    • Live/waiting form and webhook URLs include ${basePath} and function.
    • HITL: Create a step requiring approval; open the approval link from the browser under /my-n8n. Signature verification should succeed (no mismatch).
  9. Test webhook deletion

    • DELETE ${basePath}/${restEndpoint}/test-webhook/:id works.

Breaking/behavior changes

  • Health endpoints move under ${basePath}:
    • /healthz${basePath}/healthz
    • /healthz/readiness${basePath}/healthz/readiness
  • All editor assets, schemas, push, and webhook endpoints are now basePath-prefixed.
    If you previously relied on root-mounted paths while also setting N8N_PATH, update any external monitors or allowlists accordingly.

Backwards compatibility:
With N8N_PATH unset or empty, normalized basePath is '', preserving current root behavior.


Related Linear tickets, Github issues, and Community forum posts

closes #19635 (CAT-1439) — “Subpath deployment via N8N_PATH breaks: endpoints ignore basePath and Human-in-the-Loop fails”.

Review / Merge checklist

  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with release/backport (if the PR is an urgent fix that needs to be backported)

@CLAassistant

CLAassistant commented Sep 17, 2025

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@skyplane23 skyplane23 changed the title Issue/subpath basepath inconsistencies fix(cli,ui): add consistent basePath handling for subpath deployments (N8N_PATH) Sep 17, 2025
cursor[bot]

This comment was marked as outdated.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files

Prompt for AI agents (all 2 issues)

Understand the root cause of the following 2 issues and fix them.


<file name="packages/cli/src/server.ts">

<violation number="1" location="packages/cli/src/server.ts:325">
This change removes authentication from the `/types/*.json` endpoints, making them publicly accessible. This is a security regression that discloses potentially sensitive information about the instance&#39;s configured node and credential types. These endpoints should be protected by authentication as they were previously.</violation>
</file>

<file name="packages/cli/src/push/index.ts">

<violation number="1" location="packages/cli/src/push/index.ts:74">
Using pathname.includes may match unintended subpaths; use endsWith (with optional trailing slash) to target the exact push endpoint.</violation>
</file>


Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

Comment thread packages/cli/src/server.ts Outdated
Comment thread packages/cli/src/push/index.ts Outdated
cursor[bot]

This comment was marked as outdated.

@n8n-assistant n8n-assistant Bot added community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear DEPRECATED labels Sep 17, 2025
@Joffcom

Joffcom commented Sep 17, 2025

Copy link
Copy Markdown
Member

Hey @skyplane23,

Thank you for your contribution. We appreciate the time and effort you’ve taken to submit this pull request.

Before we can proceed, please ensure the following:
• Tests are included for any new functionality, logic changes or bug fixes.
• The PR aligns with our contribution guidelines.

Regarding new nodes:
We no longer accept new nodes directly into the core codebase. Instead, we encourage contributors to follow our Community Node Submission Guide to publish nodes independently.

If your node integrates with an AI service that you own or represent, please email nodes@n8n.io and we will be happy to discuss the best approach.

About review timelines:
This PR has been added to our internal tracker as "GHC-4463". While we plan to review it, we are currently unable to provide an exact timeframe. Our goal is to begin reviews within a month, but this may change depending on team priorities. We will reach out when the review begins.

Thank you again for contributing to n8n.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@tomi

tomi commented Sep 19, 2025

Copy link
Copy Markdown
Collaborator

Hi @skyplane23

Thank you for your PR. Really appreciate it. You are correct that the current support for deploying n8n under a subpath is quite lacking, and something we want to fix. Unfortunately this is breaking change for existing users who use the env var and have configured a reverse proxy to strip it out. We are currently evaluating how to handle this, but I'm personally leaning more towards introducing a new env var that adds proper support, and deprecate N8N_PATH. I will get back to you once we have clarity on this.

Regarding the implementation, we also need to scope the auth cookie to the configured subpath.

@Joffcom Joffcom added the triage:tests-needed This PR needs additional tests label Sep 20, 2025
@tomi

tomi commented Oct 8, 2025

Copy link
Copy Markdown
Collaborator

@skyplane23 we have decided the following:

  1. Leave N8N_PATH as it is. No changes should be made in its behaviour.
  2. Introduce a new N8N_BASE_PATH configuration option, which provides full support for hosting n8n under a subpath
  3. N8N_PATH will be deprecated after N8N_BASE_PATH has been implemented

So to get this merged, the following changes are needed in your PR:

  1. Get it in sync with latest changes, i.e. rebase on top of master
  2. Introduce a new configuration option N8N_BASE_PATH. Make sure it gets normalized
  3. Add a new service PathResolvingService that provides methods to resolve a full endpoint path, so it's encapsulated. Make sure it has tests
  4. Make sure the base URL is reflected in UrlService. NOTE: WEBHOOK_URL should still override the whole webhook URL
  5. Make sure auth cookies are scoped to this path

We also need e2e tests for this:

  1. We need a separate config in our e2e tests that has this new env set, in packages/testing/playwright/playwright-projects.ts. Could be named e.g. custom-base-path
  2. Create a new test suite under packages/testing/playwright/tests/ui/ which has the @mode:custom-base-path in its name. Add some basic behaviour checks into this

Make sure the current behaviour with N8N_PATH isn't changed.

If you have any questions let me know!

@skyplane23

Copy link
Copy Markdown
Author

@skyplane23 we have decided the following:

  1. Leave N8N_PATH as it is. No changes should be made in its behaviour.
  2. Introduce a new N8N_BASE_PATH configuration option, which provides full support for hosting n8n under a subpath
  3. N8N_PATH will be deprecated after N8N_BASE_PATH has been implemented

So to get this merged, the following changes are needed in your PR:

  1. Get it in sync with latest changes, i.e. rebase on top of master
  2. Introduce a new configuration option N8N_BASE_PATH. Make sure it gets normalized
  3. Add a new service PathResolvingService that provides methods to resolve a full endpoint path, so it's encapsulated. Make sure it has tests
  4. Make sure the base URL is reflected in UrlService. NOTE: WEBHOOK_URL should still override the whole webhook URL
  5. Make sure auth cookies are scoped to this path

We also need e2e tests for this:

  1. We need a separate config in our e2e tests that has this new env set, in packages/testing/playwright/playwright-projects.ts. Could be named e.g. custom-base-path
  2. Create a new test suite under packages/testing/playwright/tests/ui/ which has the @mode:custom-base-path in its name. Add some basic behaviour checks into this

Make sure the current behaviour with N8N_PATH isn't changed.

If you have any questions let me know!

Ok, I will start working on it ASAP.

@skyplane23
skyplane23 force-pushed the issue/subpath-basepath-inconsistencies branch 2 times, most recently from 624ac9e to fa487bd Compare October 10, 2025 06:02

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Comment thread packages/frontend/editor-ui/src/utils/htmlUtils.ts Outdated
Comment thread packages/frontend/editor-ui/src/utils/rbac/middleware/authenticated.ts Outdated
@skyplane23
skyplane23 force-pushed the issue/subpath-basepath-inconsistencies branch from fa487bd to e9db540 Compare January 20, 2026 08:56
@skyplane23
skyplane23 requested a review from a team January 20, 2026 08:56
@skyplane23
skyplane23 changed the base branch from master to release/1.123.16 January 20, 2026 08:57
@skyplane23

Copy link
Copy Markdown
Author

Hi! @tomi I've implemented all the requested changes:

Summary

  • N8N_BASE_PATH configuration option - Added and normalized
  • PathResolvingService - New service that encapsulates all path resolution logic (single source of truth)
  • PathResolvingService tests - Comprehensive unit tests covering all methods and edge cases
  • UrlService updated - Reflects the base path; WEBHOOK_URL still overrides the whole webhook URL
  • Auth cookies scoped - Cookies are now scoped to the base path
  • E2E tests - Added custom-base-path config in playwright-projects.ts and a new test suite with @mode:custom-base-path
  • N8N_PATH unchanged - Existing behavior preserved, works in combination with N8N_BASE_PATH
  • N8N_PATH deprecation warning - Added

All path construction throughout the codebase has been centralized into PathResolvingService, ensuring consistent URL/path handling across the application.

Before merging

I'd like to run the Playwright E2E tests locally to verify the custom-base-path tests pass. Could you point me to the recommended way to run them? I tried in my dev container but hit compatibility issues with Alpine Linux.

Question

The PR is currently outdated. Since v2 has been released, which branch should I rebase from?

Let me know if you have any questions!

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 32 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/__test__/templates.test.ts">

<violation number="1" location="packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/__test__/templates.test.ts:346">
P2: Test claims to cover missing basePath but still passes basePath via defaultParams, so defaulting logic isn’t exercised</violation>
</file>

<file name="packages/cli/src/public-api/index.ts">

<violation number="1" location="packages/cli/src/public-api/index.ts:114">
P2: Rule violated: **Prefer Typeguards over Type casting**

Avoid using `as` for type narrowing; use a type annotation instead (Rule: Prefer Typeguards over Type casting).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread packages/cli/src/public-api/index.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 28 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread packages/testing/containers/services/load-balancer.ts
Comment thread packages/cli/src/server.ts
Comment thread packages/cli/src/public-api/index.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 5 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 10 unresolved issues from previous reviews.

Re-trigger cubic

- Added basePath property to AbstractServer for dynamic endpoint management.
- Updated health check and webhook routes to utilize basePath.
- Modified ControllerRegistry to construct prefixes using basePath.
- Adjusted LoadNodesAndCredentials to resolve icons with basePath.
- Refactored Server class to pass basePath to various endpoint handlers.
- Enhanced Push class to support basePath in push endpoint setup.
…ndpoint path resolution across the application

- Added PathResolvingService to encapsulate logic for resolving full endpoint paths with the configured base path.
- Updated various components to utilize PathResolvingService for consistent URL construction, including server routes, public API endpoints, and static asset paths.
- Enhanced tests to verify correct behavior under custom base paths.
…ceBaseUrl for URL handling

- Set default value for instanceBaseUrl in createPage function to '/'.
- Refactor tests to replace basePath with instanceBaseUrl for clarity and consistency in redirect URL handling.
…ndpoint path resolution across the application

- Added PathResolvingService to encapsulate logic for resolving full endpoint paths with the configured base path.
- Updated various components to utilize PathResolvingService for consistent URL construction, including server routes, public API endpoints, and static asset paths.
- Enhanced tests to verify correct behavior under custom base paths.
…ew isolated test for custom base path functionality

- Deleted the old custom-base-path.spec.ts file which contained outdated tests.
- Introduced a new test file that verifies n8n's behavior when deployed under a custom base path, ensuring UI and API functionality is intact.
- The new tests run in an isolated container to apply the custom base path environment variable.
…unction

- Updated createPage function to ensure instanceBaseUrl is consistently normalized by adding a trailing slash if missing.
- Refactored related tests to verify correct URL handling for both absolute and relative instanceBaseUrl values, ensuring proper redirection and fetch requests.
- Updated the base URL construction to include a configurable base path, allowing n8n to be hosted under a custom path.
- Adjusted main container URL generation to append the base path, ensuring correct URL resolution for both UI and API interactions.
- Introduced new tests to verify n8n's behavior under a custom base path, including UI serving, health checks, and webhook trigger routes.
- Refactored existing tests to utilize a constant for the base path, improving maintainability and clarity.
- Ensured that routes are correctly bound to the configured base path, preventing accidental exposure at the root.
…ht tests

- Replaced the static wait strategy with a dynamic function to accommodate custom base paths in n8n.
- Updated navigation and API request handling to support base path configuration across various components.
- Improved test cases to validate behavior under custom base paths, ensuring correct URL resolution and functionality.
…solution

- Updated LoadNodesAndCredentials to handle root basePath ('/') correctly, preventing incorrect URL slicing.
- Added a test case to verify the correct behavior when resolving icons with a root basePath.
- Enhanced path resolution logic in PathResolvingService to accommodate customized health endpoints.
- Updated the normalizePathSegment function to strip multiple trailing slashes instead of just one, improving path normalization.
- Added new test cases to verify the correct behavior of normalizeBasePath when handling multiple trailing slashes.
- Removed unused Logger import from controller.registry.ts to streamline the code.
- Updated the icon resolution test to correctly handle the root basePath, ensuring accurate URL generation for icons.
- Added `assertPathAndBasePathAreNotBothSet` to enforce configuration rules for `N8N_PATH` and `N8N_BASE_PATH`.
- Updated `normalizeBasePath` to improve handling of base paths, ensuring correct normalization.
- Removed outdated tests and added new tests for `normalizeBasePath` and the new assertion function, verifying behavior under various configurations.
- Refactored related components to utilize the updated path resolution logic, ensuring consistent URL handling across the application.
- Introduced basePath property to GlobalConfig across multiple test files to ensure consistent handling of base paths.
- Updated mock configurations in tests to include basePath, enhancing test coverage for path-related functionality.
- Ensured that all relevant services and commands reflect the new basePath property for improved URL resolution.
…der custom base paths

- Modified the server to mount the overwrite endpoint middleware using the resolved path, ensuring compatibility when n8n is hosted under a custom base path.
- Removed hardcoded path usage to enhance flexibility and maintainability in URL handling.
…th resolution

- Modified the authorization endpoint in AuthService to utilize a dynamic prefix, ensuring correct URL generation under custom base paths.
- This change enhances flexibility and maintains consistency with recent updates to base path handling across the application.
…se path resolution

- Updated the DynamicCredentialsController to use PathResolvingService for constructing return URLs, ensuring correct handling of base paths.
- Enhanced tests to verify the behavior of the sign-in return URL generation, preventing duplication of the base path in the final URL.
- Modified the AbstractServer class to utilize PathResolvingService for generating the webhook waiting endpoint, enhancing flexibility in URL handling under custom base paths.
- Added support for rendering static image URLs based on the configured base path in the N8nMarkdown component.
- Introduced a new global type declaration for BASE_PATH to facilitate dynamic path resolution.
- Enhanced tests to verify correct rendering of images under both root and configured base paths.
…solution

- Updated the Server class to use PathResolvingService for resolving base paths and API endpoints, enhancing flexibility in URL handling.
- Simplified the configuration logic by removing hardcoded paths and ensuring consistent path resolution across various endpoints.
- Adjusted tests to verify the correct behavior of cookie clearing in the AuthService, ensuring proper path handling.
…mic base path resolution

- Updated the ChatTrigger templates to utilize dynamic base path resolution for login and sign-in URLs, enhancing flexibility and consistency.
- Adjusted related tests to verify the correct behavior of URL generation under various base path configurations, ensuring proper escaping of special characters.
…n redirects

- Added middleware to extract BrowserId from request headers for easier access in the Server class.
- Refactored the DynamicCredentialsController to correctly append the base path to the sign-in URL when the editor URL omits it, ensuring proper URL resolution.
- Updated tests to reflect changes in sign-in URL generation and verify correct behavior under various base path configurations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear DEPRECATED triage:complete Triage has been completed and issue is ready for internal teams triage:ready-for-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants