Files
AFFiNE-Mirror/packages/backend/server/src/server.ts
Yiding Jia a11e9fe8ca feat(server): add LISTEN_ADDR env var for allowing server to listen on ipv6 (#14211)
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.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## 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.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-01-05 09:31:47 +00:00

89 lines
2.6 KiB
TypeScript

import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import cookieParser from 'cookie-parser';
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
import {
AFFiNELogger,
CacheInterceptor,
CloudThrottlerGuard,
Config,
GlobalExceptionFilter,
URLHelper,
} from './base';
import { SocketIoAdapter } from './base/websocket';
import { AuthGuard } from './core/auth';
import { serverTimingAndCache } from './middleware/timing';
const OneMB = 1024 * 1024;
export async function run() {
const { AppModule } = await import('./app.module');
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
cors: true,
rawBody: true,
bodyParser: true,
bufferLogs: true,
});
app.useBodyParser('raw', { limit: 100 * OneMB });
const logger = app.get(AFFiNELogger);
app.useLogger(logger);
const config = app.get(Config);
if (config.server.path) {
app.setGlobalPrefix(config.server.path);
}
app.use(serverTimingAndCache);
app.use(
graphqlUploadExpress({
maxFileSize: 100 * OneMB,
maxFiles: 32,
})
);
app.useGlobalGuards(app.get(AuthGuard), app.get(CloudThrottlerGuard));
app.useGlobalInterceptors(app.get(CacheInterceptor));
app.useGlobalFilters(new GlobalExceptionFilter(app.getHttpAdapter()));
app.use(cookieParser());
// only enable shutdown hooks in production
// https://docs.nestjs.com/fundamentals/lifecycle-events#application-shutdown
if (env.prod) {
app.enableShutdownHooks();
}
const adapter = new SocketIoAdapter(app);
app.useWebSocketAdapter(adapter);
if (env.dev) {
const { SwaggerModule, DocumentBuilder } = await import('@nestjs/swagger');
// Swagger API Docs
const docConfig = new DocumentBuilder()
.setTitle('AFFiNE API')
.setDescription(`AFFiNE Server ${env.version} API documentation`)
.setVersion(`${env.version}`)
.build();
const documentFactory = () => SwaggerModule.createDocument(app, docConfig);
SwaggerModule.setup('/api/docs', app, documentFactory, {
useGlobalPrefix: true,
swaggerOptions: { persistAuthorization: true },
});
}
const url = app.get(URLHelper);
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://${formattedAddr}:${config.server.port}`);
logger.log(`And the public server should be recognized as ${url.baseUrl}`);
}