From a11e9fe8ca31a79d10d2b65f1f40b061f8400011 Mon Sep 17 00:00:00 2001 From: Yiding Jia Date: Mon, 5 Jan 2026 01:31:47 -0800 Subject: [PATCH] feat(server): add LISTEN_ADDR env var for allowing server to listen on ipv6 (#14211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old code hardcoded 0.0.0.0 which means the server only listened for ipv4 connections, making it not work on ipv6-only networks. This change adds a LISTEN_ADDR env var which allows the server to bind to ipv6 as well. ## Summary by CodeRabbit * **New Features** * Server listen address is now configurable via the LISTEN_ADDR environment variable (default: 0.0.0.0), enabling IPv4/IPv6 or interface-specific binding. * Configuration schemas and admin UI now expose the listen address option so deployments can view and override it. ✏️ Tip: You can customize this high-level summary in your review settings. --- .docker/selfhost/schema.json | 5 +++++ packages/backend/server/src/core/config/config.ts | 6 ++++++ packages/backend/server/src/server.ts | 9 ++++++--- packages/frontend/admin/src/config.json | 5 +++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.docker/selfhost/schema.json b/.docker/selfhost/schema.json index 7c25d6184..a4e9b718b 100644 --- a/.docker/selfhost/schema.json +++ b/.docker/selfhost/schema.json @@ -595,6 +595,11 @@ "description": "Multiple hosts the server will accept requests from.\n@default []", "default": [] }, + "listenAddr": { + "type": "string", + "description": "The address to listen on (e.g., 0.0.0.0 for IPv4, :: for IPv6).\n@default \"0.0.0.0\"\n@environment `LISTEN_ADDR`", + "default": "0.0.0.0" + }, "port": { "type": "number", "description": "Which port the server will listen on.\n@default 3010\n@environment `AFFINE_SERVER_PORT`", diff --git a/packages/backend/server/src/core/config/config.ts b/packages/backend/server/src/core/config/config.ts index 166e408d7..6dd8ade8e 100644 --- a/packages/backend/server/src/core/config/config.ts +++ b/packages/backend/server/src/core/config/config.ts @@ -13,6 +13,7 @@ declare global { https: boolean; host: string; hosts: ConfigItem; + listenAddr: string; port: number; path: string; name?: string; @@ -58,6 +59,11 @@ Default to be \`[server.protocol]://[server.host][:server.port]\` if not specifi default: [], shape: z.array(z.string()), }, + listenAddr: { + desc: 'The address to listen on (e.g., 0.0.0.0 for IPv4, :: for IPv6).', + default: '0.0.0.0', + env: 'LISTEN_ADDR', + }, port: { desc: 'Which port the server will listen on.', default: 3010, diff --git a/packages/backend/server/src/server.ts b/packages/backend/server/src/server.ts index a130dd9f8..558be7881 100644 --- a/packages/backend/server/src/server.ts +++ b/packages/backend/server/src/server.ts @@ -75,11 +75,14 @@ export async function run() { } const url = app.get(URLHelper); - const listeningHost = '0.0.0.0'; - await app.listen(config.server.port, listeningHost); + await app.listen(config.server.port, config.server.listenAddr); + + const formattedAddr = config.server.listenAddr.includes(':') + ? `[${config.server.listenAddr}]` + : config.server.listenAddr; logger.log(`AFFiNE Server is running in [${env.DEPLOYMENT_TYPE}] mode`); - logger.log(`Listening on http://${listeningHost}:${config.server.port}`); + logger.log(`Listening on http://${formattedAddr}:${config.server.port}`); logger.log(`And the public server should be recognized as ${url.baseUrl}`); } diff --git a/packages/frontend/admin/src/config.json b/packages/frontend/admin/src/config.json index 4288088c6..9496db797 100644 --- a/packages/frontend/admin/src/config.json +++ b/packages/frontend/admin/src/config.json @@ -216,6 +216,11 @@ "type": "Array", "desc": "Multiple hosts the server will accept requests from." }, + "listenAddr": { + "type": "String", + "desc": "The address to listen on (e.g., 0.0.0.0 for IPv4, :: for IPv6).", + "env": "LISTEN_ADDR" + }, "port": { "type": "Number", "desc": "Which port the server will listen on.",