diff --git a/next.config.ts b/next.config.ts
index a548b3c..abda98f 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -14,6 +14,12 @@ const nextConfig: NextConfig = {
images: {
remotePatterns: [{ protocol: 'https', hostname: 'avatars.githubusercontent.com', pathname: '/u/**' }],
},
+ logging: {
+ incomingRequests: {
+ // Noisy route - VSC makes a lot of requests.
+ ignore: [/^\/api\/auth-vsc\//],
+ },
+ },
}
export default nextConfig
diff --git a/nginx.conf.template b/nginx.conf.template
index be2e29c..8b4c585 100644
--- a/nginx.conf.template
+++ b/nginx.conf.template
@@ -2,6 +2,8 @@ worker_processes auto;
daemon off;
pid $NGINX_PID_PATH;
error_log $NGINX_ERROR_LOG_PATH;
+# Run worker processes as root so that they can access root-owned Unix domain sockets.
+user root;
events {
worker_connections 1024;
diff --git a/src/app/admin/components/SessionRow.tsx b/src/app/admin/components/SessionRow.tsx
index a09b197..977151a 100644
--- a/src/app/admin/components/SessionRow.tsx
+++ b/src/app/admin/components/SessionRow.tsx
@@ -23,7 +23,7 @@ export function SessionRow({ info }: { info: EditorSessionInfo }) {
{info.projectName}
- port {info.port}
+ UUID {info.sessionId}
diff --git a/src/lib/server/collabServer.ts b/src/lib/server/collabServer.ts
index 9227d15..7049774 100644
--- a/src/lib/server/collabServer.ts
+++ b/src/lib/server/collabServer.ts
@@ -54,13 +54,15 @@ export class CollabServerHandle {
// prettier-ignore
[
...BWRAP_ARGS,
+ // We don't need internet access.
+ '--unshare-net',
'--ro-bind', getCollabServerDir(), '/workspace/.collab-server',
- '--bind', this.socketDir, '/workspace/.collab-sockets',
+ '--bind', this.socketDir, '/workspace/.sockets/collab-server',
// Mount project files as writable for the collaboration server.
'--bind', this.projectDir, '/workspace/project',
'/usr/bin/node',
'/workspace/.collab-server/server.ts',
- `/workspace/.collab-sockets/${COLLAB_SOCKET_FILENAME}`,
+ `/workspace/.sockets/collab-server/${COLLAB_SOCKET_FILENAME}`,
'/workspace/project',
],
{ stdio: 'inherit' },
diff --git a/src/lib/server/editorSessions.ts b/src/lib/server/editorSessions.ts
index 9d24c09..439c7c6 100644
--- a/src/lib/server/editorSessions.ts
+++ b/src/lib/server/editorSessions.ts
@@ -16,12 +16,8 @@ export interface EditorSessionInfo {
ownerUsername: string
projectId: string
projectName: string
- port: number
}
-const BASE_PORT = 3010
-const MAX_PORT = 3999
-
export class EditorSessionManager {
/** projectId ↦ [servers for that project]
*
@@ -42,8 +38,6 @@ export class EditorSessionManager {
* Same invariant as in {@link vscServers}. */
private collabServers = new Map()
- private availablePorts = new Set(Array.from({ length: MAX_PORT - BASE_PORT + 1 }, (_, i) => BASE_PORT + i))
-
constructor() {
this.vscServerEvents.addListener('close', s => {
if ((this.vscServers.get(s.project.id) ?? []).length === 0) {
@@ -81,20 +75,15 @@ export class EditorSessionManager {
const projectSessions = this.vscServers.get(project.id) ?? []
let session = projectSessions.find(s => s.viewer.id === viewer.id)
if (!session) {
- const port = this.availablePorts.values().next().value
- if (port === undefined) throw new Error('no available ports')
- this.availablePorts.delete(port)
-
const projectDir = path.join(getWorkspacesDir(), owner.name, project.id)
const collabServer = this.findCollabServer(project, projectDir)
- session = new VscodeServerHandle(viewer, owner, project, projectDir, collabServer.socketDir, port)
+ session = new VscodeServerHandle(viewer, owner, project, projectDir, collabServer.socketDir)
session.addDisposable(async () => {
this.vscServers.set(
project.id,
(this.vscServers.get(project.id) ?? []).filter(s => s !== session),
)
this.vscServerEvents.emit('close', session!)
- this.availablePorts.add(port)
})
// Insertion happens in same transaction as failed lookup (before any `await`)
this.vscServers.set(project.id, [...(this.vscServers.get(project.id) ?? []), session])
@@ -154,7 +143,6 @@ export class EditorSessionManager {
ownerUsername: project.user.name,
projectId,
projectName: project.name,
- port: s.port,
})
}
}
diff --git a/src/lib/server/vscodeServer.ts b/src/lib/server/vscodeServer.ts
index c2d0965..1f9134a 100644
--- a/src/lib/server/vscodeServer.ts
+++ b/src/lib/server/vscodeServer.ts
@@ -65,6 +65,9 @@ async function waitForNginxRoute(path: string, timeoutMs = 10_000): Promise {
+ await fs.rm(this.socketDir, { recursive: true, force: true })
+ })
+
// Every user gets their own VSCode server configuration, and set of installed extensions.
// Openvscode-server derives --user-data-dir and --extensions-dir from --server-data-dir:
// https://github.com/gitpod-io/openvscode-server/blob/2bfb814c5215c51a10e80c2cb1b58ed91068ad8b/src/vs/server/node/server.main.ts
@@ -193,7 +201,8 @@ export class VscodeServerHandle {
// but users can still write files directly if needed.
// Lake and other CLI tools do such writes.
'--bind', this.projectDir, sandboxProjectDir,
- '--bind', this.collabSocketDir, '/workspace/.collab-sockets',
+ '--bind', this.collabSocketDir, '/workspace/.sockets/collab-server',
+ '--bind', this.socketDir, '/workspace/.sockets/openvscode-server',
...overlayArgs,
'--setenv', 'HOME', '/workspace',
'--setenv', 'ELAN_HOME', '/workspace/.elan',
@@ -208,8 +217,7 @@ export class VscodeServerHandle {
...devArgs,
'--',
'/workspace/.openvscode-server/bin/openvscode-server',
- '--host', '127.0.0.1',
- '--port', String(this.port),
+ '--socket-path', `/workspace/.sockets/openvscode-server/${VSCODE_SOCKET_FILENAME}`,
'--without-connection-token',
`--server-base-path=${this.vscodeIframePath}`,
'--server-data-dir', '/workspace/.vscode-remote',