Skip to content

Conversation

datnguyennnx
Copy link

@datnguyennnx datnguyennnx commented Sep 19, 2025

Feature: BasePath Support for Subpath Deployments

Problem

Self-hosted users cannot deploy HyperDX under custom subpaths with nginx/traefik reverse proxies (e.g., domain.com/hyperdx).

Current User Pain: Users who want subpath deployment have to:

  • Fork the repository and maintain custom builds
  • Manually modify source code for every update
  • Miss out on official Docker image updates
  • Manage their own build pipeline and maintenance

Solution: Docker Environment Variable Approach

Added three environment variables to enable subpath deployment without requiring source code modifications:

  • HYPERDX_BASE_PATH - Frontend Next.js basePath (e.g., /hyperdx)
  • HYPERDX_API_BASE_PATH - Backend API basePath (e.g., /hyperdx/api)
  • HYPERDX_OTEL_BASE_PATH - OTEL collector basePath (e.g., /hyperdx/otel)

Key Innovation: Use Official Docker Images + Environment Variables

Before (Complex):

# Users had to maintain custom builds
git clone hyperdx
# Modify source files manually
# Build custom Docker image  
# Miss official updates
# Maintain fork forever

After (Simple):

# Users just pull official images and set env vars
docker pull hyperdx/hyperdx:latest
# Set environment variables in docker-compose.yml or .env
# Deploy with basePath - that's it!
# Get updates automatically with official images

Benefits

For Users:

  • Easy Updates: Pull latest HyperDX images without losing basePath configuration
  • No Source Maintenance: No need to fork repository or maintain custom builds
  • Production Ready: Uses official Docker images with runtime configuration
  • Zero Setup: Just set environment variables and deploy

For HyperDX Project:

  • Wider Adoption: Enables enterprise deployment scenarios without support burden
  • Lower Maintenance: Users don't create forks or custom builds
  • Standard Pattern: Follows Docker environment variable best practices
  • Backward Compatible: Existing deployments work exactly the same

Usage Example

Docker Compose Deployment

# docker-compose.yml
services:
  app:
    image: hyperdx/hyperdx:latest
    environment:
      HYPERDX_BASE_PATH: /hyperdx
      HYPERDX_API_BASE_PATH: /hyperdx/api
      HYPERDX_OTEL_BASE_PATH: /hyperdx/otel

Environment Variables

# Set in .env file
HYPERDX_BASE_PATH=/hyperdx
HYPERDX_API_BASE_PATH=/hyperdx/api
HYPERDX_OTEL_BASE_PATH=/hyperdx/otel

nginx Reverse Proxy

# nginx.conf
location /hyperdx/ {
    proxy_pass http://hyperdx-container:8080/hyperdx/;
    proxy_set_header Host $host;
}

Deployment Patterns Enabled

  • https://domain.com/hyperdx → HyperDX frontend
  • https://domain.com/hyperdx/api → HyperDX API
  • https://domain.com/hyperdx/otel → OTEL collector

Update Workflow Improvement

Traditional Approach (Maintenance Burden):

# User maintains fork
git pull upstream/main
# Resolve merge conflicts in modified files
# Rebuild custom Docker image
# Test everything again

Our Approach (Effortless Updates):

# User gets latest official image
docker pull hyperdx/hyperdx:latest
docker-compose up -d
# Same environment variables, new features automatically

Testing

  • Verified working at /hyperdx subpath
  • All API endpoints respond correctly (/hyperdx/api/config, /hyperdx/api/health)
  • Docker production build successful
  • Frontend assets load with correct basePath
  • Backward compatibility maintained

Files Modified

  • packages/app/next.config.js
  • packages/app/src/api.ts
  • packages/app/pages/api/[...all].ts
  • packages/api/src/api-app.ts
  • packages/api/src/opamp/app.ts
  • docker-compose.yml
  • docker/hyperdx/Dockerfile
  • Makefile

Impact

This addresses a common deployment need for self-hosted users who want to run HyperDX under reverse proxies with custom paths without the maintenance burden of custom builds.

Result: Transform HyperDX from "clone sources and modify code" to "pull official image and set environment variables" - enabling enterprise deployment flexibility while maintaining the official update path.

Copy link

changeset-bot bot commented Sep 19, 2025

🦋 Changeset detected

Latest commit: 70fa0a7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Minor
@hyperdx/api Minor
@hyperdx/common-utils Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

vercel bot commented Sep 19, 2025

@datnguyennnx is attempting to deploy a commit to the HyperDX Team on Vercel.

A member of the Team first needs to authorize it.

@wrn14897
Copy link
Member

I don’t think this change is necessary. The /api route is already proxied on the Next.js server side. For production deployments, we recommend using the HyperDX Helm charts
, which leverage a fullstack build.

Additionally, the OpAMP endpoint should not be exposed (it runs on the same API server but on a different port), so I don’t see a reason to introduce a reverse proxy in this case. If you want to prefix a subpath, I’d suggest configuring that at your reverse proxy layer.

@datnguyennnx
Copy link
Author

datnguyennnx commented Sep 21, 2025

From my experience, setting up subpaths using only Traefik/nginx is tough and often breaks URLs.
Example from our Traefik config:

middlewares:
  hyperdx-strip-prefix:
    stripPrefix:
      prefixes:
        - "/hyperdx"
routers:
  hyperdx-app-router:
    rule: 'PathPrefix(`/hyperdx`) || PathPrefix(`/api`)  || PathPrefix(`/_next`) || PathPrefix(`/__ENV.js`)'
    middlewares:
      - 'hyperdx-strip-prefix'
services:
   hyperdx-app-service:
     loadBalancer:
       servers:
       - url: 'http://hyperdx-app:8050'

Even with this setup, many frontend links break or ignore /hyperdx and redirect to root paths, causing broken navigation.

This shows how hard it is to handle subpaths fully in proxy layer. Having basePath config inside the app itself is much simpler and more reliable.

The OpAMP endpoint is fine (if you accept this, I’ll remove the OpAMP endpoint—we only expose the API and app endpoint).

@wrn14897
Copy link
Member

Thanks for the effort here — I see the motivation to make updating the URL subpath easier, and that’s definitely valuable. That said, I have a few concerns with the current approach:

  • Backward compatibility – This change risks breaking existing setups.
  • Environment variable in next.config.js or _document.tsx – It doesn’t work dynamically, and I suspect it still requires an image rebuild.
  • Code duplication – The repeated logic makes the code harder to read and maintain.
  • Subpath switching – It’s still unclear how well this works in local mode.

For context: this proxy issue was problematic in HyperDX v1, but with the flexibility of Helm deployments and the internal API proxy (removing the need to deploy both services), things should already be simpler.

I agree that configuring subpaths is a bit annoying. However, I think we should take a step back before spreading environment variables across the codebase in ways that risk breaking existing behavior. There might be a cleaner approach.

Suggestion:
If you’re open to it, I’d propose creating a new proxy/ directory with Traefik or Nginx configs. I’d be happy to help review and make sure that works smoothly.

@datnguyennnx
Copy link
Author

datnguyennnx commented Sep 27, 2025

  • Proxy-Centric: New proxy/ dir with Nginx/Traefik configs, no OpAMP exposure.
  • Backward Compat: Defaults to '/' (root unchanged); E2E verified no regressions.
  • Dynamic/No Rebuild: Runtime process.env via centralized utils (basePath.ts)
  • No Duplication: All env reads in utils; refactors in 5 files use get*BasePath()

All problems solved, please re-review and test. Ready to merge!

@datnguyennnx datnguyennnx force-pushed the feat/add-basepath-support branch from 3e5b0d1 to 007bf4f Compare September 27, 2025 09:19
Makefile Outdated
Comment on lines 113 to 115
--build-arg HYPERDX_BASE_PATH="${HYPERDX_BASE_PATH}" \
--build-arg HYPERDX_API_BASE_PATH="${HYPERDX_API_BASE_PATH}" \
--build-arg HYPERDX_OTEL_BASE_PATH="${HYPERDX_OTEL_BASE_PATH}" \
Copy link
Member

@wrn14897 wrn14897 Sep 29, 2025

Choose a reason for hiding this comment

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

does this mean that devs need to rebuild the image whenever the env var changes?

Copy link
Author

Choose a reason for hiding this comment

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

@wrn14897 No rebuild needed! Those build-args were a holdover from an earlier iteration - I've removed them entirely from the Makefile.

The base paths are now read at runtime via process.env in centralized utils (basePath.ts), so you can switch subpaths dynamically with docker run -e HYPERDX_BASE_PATH=/hyperdx or compose restart - no image rebuilds required. Verified: Build once (make build-app), run root → subpath via -e, and curls/UI/API prefix correctly (e.g., /hyperdx/api/health 200 OK).

This aligns with your dynamic config concern. Please re-review—tests/E2E confirm no regressions!

@wrn14897
Copy link
Member

wrn14897 commented Sep 29, 2025

  • Proxy-Centric: New proxy/ dir with Nginx/Traefik configs, no OpAMP exposure.
  • Backward Compat: Defaults to '/' (root unchanged); E2E verified no regressions.
  • Dynamic/No Rebuild: Runtime process.env via centralized utils (basePath.ts)
  • No Duplication: All env reads in utils; refactors in 5 files use get*BasePath()

All problems solved, please re-review and test. Ready to merge!

Thanks for following up, @datnguyennnx . I may not have explained it clearly earlier. The /api should be proxied by the nextjs server, and in most cases people won’t really care about what the API base path is (since the API and app are effectively bundled together in a single build).

So for example, if the subpath is foo, the API route should resolve to foo/api. My preference is to handle this primarily at the proxy layer, minimizing changes to the application code.
I’ve created a branch with a proof of concept here: link
. In theory, the only required changes are injecting HYPERDX_BASE_PATH into next.config.js and updating FRONTEND_URL. Once the nextjs server restarts and picks up the new config, the subpath should work as expected.

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