Skip to content

Commit 5b905c3

Browse files
committed
feat: add basepath config
1 parent 0183483 commit 5b905c3

File tree

12 files changed

+112
-42
lines changed

12 files changed

+112
-42
lines changed

.env

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ HYPERDX_APP_PORT=8080
2020
HYPERDX_APP_URL=http://localhost
2121
HYPERDX_LOG_LEVEL=debug
2222
HYPERDX_OPAMP_PORT=4320
23+
HYPERDX_BASE_PATH=/hyperdx
24+
HYPERDX_API_BASE_PATH=/hyperdx/api
25+
HYPERDX_OTEL_BASE_PATH=/hyperdx/otel
2326

2427
# Otel/Clickhouse config
2528
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=default

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ build-app:
110110
--build-context api=./packages/api \
111111
--build-context app=./packages/app \
112112
--build-arg CODE_VERSION=${CODE_VERSION} \
113+
--build-arg HYPERDX_BASE_PATH="${HYPERDX_BASE_PATH}" \
114+
--build-arg HYPERDX_API_BASE_PATH="${HYPERDX_API_BASE_PATH}" \
115+
--build-arg HYPERDX_OTEL_BASE_PATH="${HYPERDX_OTEL_BASE_PATH}" \
113116
-t ${IMAGE_NAME_DOCKERHUB}:${IMAGE_VERSION}${IMAGE_VERSION_SUB_TAG} \
114117
--target prod
115118

docker-compose.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ services:
3232
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE: ${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE}
3333
HYPERDX_LOG_LEVEL: ${HYPERDX_LOG_LEVEL}
3434
OPAMP_SERVER_URL: 'http://app:${HYPERDX_OPAMP_PORT}'
35+
HYPERDX_OTEL_BASE_PATH: ${HYPERDX_OTEL_BASE_PATH:-}
3536
ports:
3637
- '13133:13133' # health_check extension
3738
- '24225:24225' # fluentd receiver
@@ -62,6 +63,9 @@ services:
6263
OTEL_EXPORTER_OTLP_ENDPOINT: 'http://otel-collector:4318'
6364
OTEL_SERVICE_NAME: 'hdx-oss-app'
6465
USAGE_STATS_ENABLED: ${USAGE_STATS_ENABLED:-true}
66+
HYPERDX_BASE_PATH: ${HYPERDX_BASE_PATH:-}
67+
HYPERDX_API_BASE_PATH: ${HYPERDX_API_BASE_PATH:-}
68+
HYPERDX_OTEL_BASE_PATH: ${HYPERDX_OTEL_BASE_PATH:-}
6569
DEFAULT_CONNECTIONS:
6670
'[{"name":"Local
6771
ClickHouse","host":"http://ch-server:8123","username":"default","password":""}]'

docker/hyperdx/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ RUN yarn install --mode=skip-build && yarn cache clean
3636
## API/APP Builder Image ##########################################################################
3737
FROM node_base AS builder
3838

39+
ARG HYPERDX_BASE_PATH
40+
ARG HYPERDX_API_BASE_PATH
41+
ARG HYPERDX_OTEL_BASE_PATH
42+
3943
WORKDIR /app
4044

4145
COPY --from=api ./src ./packages/api/src
@@ -48,6 +52,9 @@ COPY --from=app ./types ./packages/app/types
4852
ENV NEXT_TELEMETRY_DISABLED 1
4953
ENV NEXT_OUTPUT_STANDALONE true
5054
ENV NEXT_PUBLIC_IS_LOCAL_MODE false
55+
ENV HYPERDX_BASE_PATH $HYPERDX_BASE_PATH
56+
ENV HYPERDX_API_BASE_PATH $HYPERDX_API_BASE_PATH
57+
ENV HYPERDX_OTEL_BASE_PATH $HYPERDX_OTEL_BASE_PATH
5158
ENV NX_DAEMON=false
5259
RUN npx nx run-many --target=build --projects=@hyperdx/common-utils,@hyperdx/api,@hyperdx/app
5360

packages/api/src/api-app.ts

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import passport from './utils/passport';
2020

2121
const app: express.Application = express();
2222

23+
const API_BASE_PATH = process.env.HYPERDX_API_BASE_PATH || '';
24+
2325
const sess: session.SessionOptions & { cookie: session.CookieOptions } = {
2426
resave: false,
2527
saveUninitialized: false,
@@ -79,45 +81,84 @@ if (config.USAGE_STATS_ENABLED) {
7981
// ---------------------------------------------------------------------
8082
// ----------------------- Internal Routers ----------------------------
8183
// ---------------------------------------------------------------------
82-
// PUBLIC ROUTES
83-
app.use('/', routers.rootRouter);
84+
if (API_BASE_PATH) {
85+
const apiRouter = express.Router();
86+
87+
// PUBLIC ROUTES
88+
apiRouter.use('/', routers.rootRouter);
89+
90+
// PRIVATE ROUTES
91+
apiRouter.use('/alerts', isUserAuthenticated, routers.alertsRouter);
92+
apiRouter.use('/dashboards', isUserAuthenticated, routers.dashboardRouter);
93+
apiRouter.use('/me', isUserAuthenticated, routers.meRouter);
94+
apiRouter.use('/team', isUserAuthenticated, routers.teamRouter);
95+
apiRouter.use('/webhooks', isUserAuthenticated, routers.webhooksRouter);
96+
apiRouter.use('/connections', isUserAuthenticated, connectionsRouter);
97+
apiRouter.use('/sources', isUserAuthenticated, sourcesRouter);
98+
apiRouter.use('/saved-search', isUserAuthenticated, savedSearchRouter);
99+
apiRouter.use('/clickhouse-proxy', isUserAuthenticated, clickhouseProxyRouter);
100+
apiRouter.use('/api/v2', externalRoutersV2);
101+
102+
// Only initialize Swagger in development or if explicitly enabled
103+
if (
104+
process.env.NODE_ENV !== 'production' &&
105+
process.env.ENABLE_SWAGGER === 'true'
106+
) {
107+
import('./utils/swagger')
108+
.then(({ setupSwagger }) => {
109+
console.log('Swagger UI setup and available at /api/v2/docs');
110+
setupSwagger(app);
111+
})
112+
.catch(error => {
113+
console.error(
114+
'Failed to dynamically load or setup Swagger. Swagger UI will not be available.',
115+
error,
116+
);
117+
});
118+
}
119+
120+
app.use(API_BASE_PATH, apiRouter);
121+
} else {
122+
// PUBLIC ROUTES
123+
app.use('/', routers.rootRouter);
84124

85-
// PRIVATE ROUTES
86-
app.use('/alerts', isUserAuthenticated, routers.alertsRouter);
87-
app.use('/dashboards', isUserAuthenticated, routers.dashboardRouter);
88-
app.use('/me', isUserAuthenticated, routers.meRouter);
89-
app.use('/team', isUserAuthenticated, routers.teamRouter);
90-
app.use('/webhooks', isUserAuthenticated, routers.webhooksRouter);
91-
app.use('/connections', isUserAuthenticated, connectionsRouter);
92-
app.use('/sources', isUserAuthenticated, sourcesRouter);
93-
app.use('/saved-search', isUserAuthenticated, savedSearchRouter);
94-
app.use('/clickhouse-proxy', isUserAuthenticated, clickhouseProxyRouter);
95-
// ---------------------------------------------------------------------
125+
// PRIVATE ROUTES
126+
app.use('/alerts', isUserAuthenticated, routers.alertsRouter);
127+
app.use('/dashboards', isUserAuthenticated, routers.dashboardRouter);
128+
app.use('/me', isUserAuthenticated, routers.meRouter);
129+
app.use('/team', isUserAuthenticated, routers.teamRouter);
130+
app.use('/webhooks', isUserAuthenticated, routers.webhooksRouter);
131+
app.use('/connections', isUserAuthenticated, connectionsRouter);
132+
app.use('/sources', isUserAuthenticated, sourcesRouter);
133+
app.use('/saved-search', isUserAuthenticated, savedSearchRouter);
134+
app.use('/clickhouse-proxy', isUserAuthenticated, clickhouseProxyRouter);
135+
136+
// TODO: Separate external API routers from internal routers
137+
// ---------------------------------------------------------------------
138+
// ----------------------- External Routers ----------------------------
139+
// ---------------------------------------------------------------------
140+
// API v2
141+
// Only initialize Swagger in development or if explicitly enabled
142+
if (
143+
process.env.NODE_ENV !== 'production' &&
144+
process.env.ENABLE_SWAGGER === 'true'
145+
) {
146+
import('./utils/swagger')
147+
.then(({ setupSwagger }) => {
148+
console.log('Swagger UI setup and available at /api/v2/docs');
149+
setupSwagger(app);
150+
})
151+
.catch(error => {
152+
console.error(
153+
'Failed to dynamically load or setup Swagger. Swagger UI will not be available.',
154+
error,
155+
);
156+
});
157+
}
96158

97-
// TODO: Separate external API routers from internal routers
98-
// ---------------------------------------------------------------------
99-
// ----------------------- External Routers ----------------------------
100-
// ---------------------------------------------------------------------
101-
// API v2
102-
// Only initialize Swagger in development or if explicitly enabled
103-
if (
104-
process.env.NODE_ENV !== 'production' &&
105-
process.env.ENABLE_SWAGGER === 'true'
106-
) {
107-
import('./utils/swagger')
108-
.then(({ setupSwagger }) => {
109-
console.log('Swagger UI setup and available at /api/v2/docs');
110-
setupSwagger(app);
111-
})
112-
.catch(error => {
113-
console.error(
114-
'Failed to dynamically load or setup Swagger. Swagger UI will not be available.',
115-
error,
116-
);
117-
});
159+
app.use('/api/v2', externalRoutersV2);
118160
}
119-
120-
app.use('/api/v2', externalRoutersV2);
161+
// ---------------------------------------------------------------------
121162

122163
// error handling
123164
app.use(appErrorHandler);

packages/api/src/opamp/app.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ import { opampController } from '@/opamp/controllers/opampController';
66
// Create Express application
77
const app = express();
88

9+
const OTEL_BASE_PATH = process.env.HYPERDX_OTEL_BASE_PATH || '';
10+
911
app.disable('x-powered-by');
1012

1113
// Special body parser setup for OpAMP
1214
app.use(
13-
'/v1/opamp',
15+
`${OTEL_BASE_PATH}/v1/opamp`,
1416
express.raw({
1517
type: 'application/x-protobuf',
1618
limit: '10mb',
1719
}),
1820
);
1921

2022
// OpAMP endpoint
21-
app.post('/v1/opamp', opampController.handleOpampMessage.bind(opampController));
23+
app.post(`${OTEL_BASE_PATH}/v1/opamp`, opampController.handleOpampMessage.bind(opampController));
2224

2325
// Health check endpoint
2426
app.get('/health', (req, res) => {

packages/app/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ FROM base AS builder
2828
ARG OTEL_EXPORTER_OTLP_ENDPOINT
2929
ARG OTEL_SERVICE_NAME
3030
ARG IS_LOCAL_MODE
31+
ARG HYPERDX_BASE_PATH
3132
ENV NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT $OTEL_EXPORTER_OTLP_ENDPOINT
3233
ENV NEXT_PUBLIC_OTEL_SERVICE_NAME $OTEL_SERVICE_NAME
3334
ENV NEXT_PUBLIC_IS_LOCAL_MODE $IS_LOCAL_MODE
35+
ENV HYPERDX_BASE_PATH $HYPERDX_BASE_PATH
3436
ENV NX_DAEMON false
3537

3638
COPY ./packages/app/src ./packages/app/src

packages/app/next.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const withNextra = require('nextra')({
99
});
1010

1111
module.exports = {
12+
basePath: process.env.HYPERDX_BASE_PATH || '',
1213
experimental: {
1314
instrumentationHook: true,
1415
// External packages to prevent bundling issues with Next.js 14

packages/app/pages/_document.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default function Document() {
44
return (
55
<Html lang="en">
66
<Head>
7-
<script src="/__ENV.js" />
7+
<script src={`${process.env.HYPERDX_BASE_PATH || ''}/__ENV.js`} />
88
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.2/full/pyodide.js"></script>
99
<link
1010
rel="stylesheet"

packages/app/pages/api/[...all].ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
22
import { createProxyMiddleware, fixRequestBody } from 'http-proxy-middleware';
33

44
const DEFAULT_SERVER_URL = `http://127.0.0.1:${process.env.HYPERDX_API_PORT}`;
5+
const API_BASE_PATH = process.env.HYPERDX_API_BASE_PATH || '';
56

67
export const config = {
78
api: {
@@ -14,7 +15,7 @@ export default (req: NextApiRequest, res: NextApiResponse) => {
1415
const proxy = createProxyMiddleware({
1516
changeOrigin: true,
1617
// logger: console, // DEBUG
17-
pathRewrite: { '^/api': '' },
18+
pathRewrite: { '^/api': API_BASE_PATH },
1819
target: process.env.SERVER_URL || DEFAULT_SERVER_URL,
1920
autoRewrite: true,
2021
// ...(IS_DEV && {

0 commit comments

Comments
 (0)