mirror of https://github.com/coder/code-server.git
feat: introduce --abs-proxy-base-path that allows app proxying while code-server is not server at the root.
This commit is contained in:
parent
39ce82a44d
commit
f8a4da7667
|
@ -432,3 +432,12 @@ const config = {
|
||||||
3. Access app at `<code-server-root>/absproxy/5173/` e.g. `http://localhost:8080/absproxy/5173/
|
3. Access app at `<code-server-root>/absproxy/5173/` e.g. `http://localhost:8080/absproxy/5173/
|
||||||
|
|
||||||
For additional context, see [this Github Issue](https://github.com/sveltejs/kit/issues/2958)
|
For additional context, see [this Github Issue](https://github.com/sveltejs/kit/issues/2958)
|
||||||
|
|
||||||
|
### Prefixing `/absproxy/<port>` with a path
|
||||||
|
|
||||||
|
This is a case where you need to serve an application via `absproxy` as explained above while serving `codeserver` itself from a path other than the root in your domain.
|
||||||
|
|
||||||
|
For example: `http://my-code-server.com/user/123/workspace/my-app`. To achieve this result:
|
||||||
|
|
||||||
|
1. start code server with the switch `--abs-proxy-base-path=/user/123/workspace`
|
||||||
|
2. Follow one of the instructions above for your framework.
|
||||||
|
|
|
@ -53,6 +53,7 @@ export interface UserProvidedCodeArgs {
|
||||||
"disable-getting-started-override"?: boolean
|
"disable-getting-started-override"?: boolean
|
||||||
"disable-proxy"?: boolean
|
"disable-proxy"?: boolean
|
||||||
"session-socket"?: string
|
"session-socket"?: string
|
||||||
|
"abs-proxy-base-path"?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,18 +118,18 @@ interface Option<T> {
|
||||||
type OptionType<T> = T extends boolean
|
type OptionType<T> = T extends boolean
|
||||||
? "boolean"
|
? "boolean"
|
||||||
: T extends OptionalString
|
: T extends OptionalString
|
||||||
? typeof OptionalString
|
? typeof OptionalString
|
||||||
: T extends LogLevel
|
: T extends LogLevel
|
||||||
? typeof LogLevel
|
? typeof LogLevel
|
||||||
: T extends AuthType
|
: T extends AuthType
|
||||||
? typeof AuthType
|
? typeof AuthType
|
||||||
: T extends number
|
: T extends number
|
||||||
? "number"
|
? "number"
|
||||||
: T extends string
|
: T extends string
|
||||||
? "string"
|
? "string"
|
||||||
: T extends string[]
|
: T extends string[]
|
||||||
? "string[]"
|
? "string[]"
|
||||||
: "unknown"
|
: "unknown"
|
||||||
|
|
||||||
export type Options<T> = {
|
export type Options<T> = {
|
||||||
[P in keyof T]: Option<OptionType<T[P]>>
|
[P in keyof T]: Option<OptionType<T[P]>>
|
||||||
|
@ -279,6 +280,10 @@ export const options: Options<Required<UserProvidedArgs>> = {
|
||||||
short: "w",
|
short: "w",
|
||||||
description: "Text to show on login page",
|
description: "Text to show on login page",
|
||||||
},
|
},
|
||||||
|
"abs-proxy-base-path": {
|
||||||
|
type: "string",
|
||||||
|
description: "The base path to prefix all absproxy requests",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const optionDescriptions = (opts: Partial<Options<Required<UserProvidedArgs>>> = options): string[] => {
|
export const optionDescriptions = (opts: Partial<Options<Required<UserProvidedArgs>>> = options): string[] => {
|
||||||
|
|
|
@ -121,11 +121,13 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
|
||||||
app.router.all("/absproxy/:port/:path(.*)?", async (req, res) => {
|
app.router.all("/absproxy/:port/:path(.*)?", async (req, res) => {
|
||||||
await pathProxy.proxy(req, res, {
|
await pathProxy.proxy(req, res, {
|
||||||
passthroughPath: true,
|
passthroughPath: true,
|
||||||
|
proxyBasePath: args["abs-proxy-base-path"],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
app.wsRouter.get("/absproxy/:port/:path(.*)?", async (req) => {
|
app.wsRouter.get("/absproxy/:port/:path(.*)?", async (req) => {
|
||||||
await pathProxy.wsProxy(req as pluginapi.WebsocketRequest, {
|
await pathProxy.wsProxy(req as pluginapi.WebsocketRequest, {
|
||||||
passthroughPath: true,
|
passthroughPath: true,
|
||||||
|
proxyBasePath: args["abs-proxy-base-path"],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,15 @@ import { HttpCode, HttpError } from "../../common/http"
|
||||||
import { ensureProxyEnabled, authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
|
import { ensureProxyEnabled, authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
|
||||||
import { proxy as _proxy } from "../proxy"
|
import { proxy as _proxy } from "../proxy"
|
||||||
|
|
||||||
const getProxyTarget = (req: Request): string => {
|
const getProxyTarget = (
|
||||||
|
req: Request,
|
||||||
|
opts?: {
|
||||||
|
proxyBasePath?: string
|
||||||
|
},
|
||||||
|
): string => {
|
||||||
// If there is a base path, strip it out.
|
// If there is a base path, strip it out.
|
||||||
const base = (req as any).base || ""
|
const base = (req as any).base || ""
|
||||||
return `http://0.0.0.0:${req.params.port}/${req.originalUrl.slice(base.length)}`
|
return `http://0.0.0.0:${req.params.port}${opts?.proxyBasePath || ""}/${req.originalUrl.slice(base.length)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function proxy(
|
export async function proxy(
|
||||||
|
@ -16,6 +21,7 @@ export async function proxy(
|
||||||
res: Response,
|
res: Response,
|
||||||
opts?: {
|
opts?: {
|
||||||
passthroughPath?: boolean
|
passthroughPath?: boolean
|
||||||
|
proxyBasePath?: string
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
ensureProxyEnabled(req)
|
ensureProxyEnabled(req)
|
||||||
|
@ -38,7 +44,7 @@ export async function proxy(
|
||||||
|
|
||||||
_proxy.web(req, res, {
|
_proxy.web(req, res, {
|
||||||
ignorePath: true,
|
ignorePath: true,
|
||||||
target: getProxyTarget(req),
|
target: getProxyTarget(req, opts),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +52,7 @@ export async function wsProxy(
|
||||||
req: pluginapi.WebsocketRequest,
|
req: pluginapi.WebsocketRequest,
|
||||||
opts?: {
|
opts?: {
|
||||||
passthroughPath?: boolean
|
passthroughPath?: boolean
|
||||||
|
proxyBasePath?: string
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
ensureProxyEnabled(req)
|
ensureProxyEnabled(req)
|
||||||
|
@ -59,6 +66,6 @@ export async function wsProxy(
|
||||||
|
|
||||||
_proxy.ws(req, req.ws, req.head, {
|
_proxy.ws(req, req.ws, req.head, {
|
||||||
ignorePath: true,
|
ignorePath: true,
|
||||||
target: getProxyTarget(req),
|
target: getProxyTarget(req, opts),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,8 @@ describe("parser", () => {
|
||||||
|
|
||||||
"--disable-proxy",
|
"--disable-proxy",
|
||||||
|
|
||||||
|
["--abs-proxy-base-path", "/codeserver/app1"],
|
||||||
|
|
||||||
["--session-socket", "/tmp/override-code-server-ipc-socket"],
|
["--session-socket", "/tmp/override-code-server-ipc-socket"],
|
||||||
|
|
||||||
["--host", "0.0.0.0"],
|
["--host", "0.0.0.0"],
|
||||||
|
@ -143,6 +145,7 @@ describe("parser", () => {
|
||||||
version: true,
|
version: true,
|
||||||
"bind-addr": "192.169.0.1:8080",
|
"bind-addr": "192.169.0.1:8080",
|
||||||
"session-socket": "/tmp/override-code-server-ipc-socket",
|
"session-socket": "/tmp/override-code-server-ipc-socket",
|
||||||
|
"abs-proxy-base-path": "/codeserver/app1",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -256,6 +256,18 @@ describe("proxy", () => {
|
||||||
expect(spy).toHaveBeenCalledWith([test.expected, test.query])
|
expect(spy).toHaveBeenCalledWith([test.expected, test.query])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should allow specifying an absproxy path", async () => {
|
||||||
|
const prefixedPath = `/codeserver/app1${absProxyPath}`
|
||||||
|
e.get(prefixedPath, (req, res) => {
|
||||||
|
res.send("app being served behind a prefixed path")
|
||||||
|
})
|
||||||
|
codeServer = await integration.setup(["--auth=none", "--abs-proxy-base-path=/codeserver/app1"], "")
|
||||||
|
const resp = await codeServer.fetch(absProxyPath)
|
||||||
|
expect(resp.status).toBe(200)
|
||||||
|
const text = await resp.text()
|
||||||
|
expect(text).toBe("app being served behind a prefixed path")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// NOTE@jsjoeio
|
// NOTE@jsjoeio
|
||||||
|
|
Loading…
Reference in New Issue