mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(core): Port path, host, port, listen_address and protocol config (no-changelog) (#10223)
This commit is contained in:
parent
4d37b9669f
commit
7a30d845e9
|
@ -1,4 +1,4 @@
|
||||||
import { Config, Nested } from './decorators';
|
import { Config, Env, Nested } from './decorators';
|
||||||
import { CredentialsConfig } from './configs/credentials';
|
import { CredentialsConfig } from './configs/credentials';
|
||||||
import { DatabaseConfig } from './configs/database';
|
import { DatabaseConfig } from './configs/database';
|
||||||
import { EmailConfig } from './configs/email';
|
import { EmailConfig } from './configs/email';
|
||||||
|
@ -51,4 +51,24 @@ export class GlobalConfig {
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly workflows: WorkflowsConfig;
|
readonly workflows: WorkflowsConfig;
|
||||||
|
|
||||||
|
/** Path n8n is deployed to */
|
||||||
|
@Env('N8N_PATH')
|
||||||
|
readonly path: string = '/';
|
||||||
|
|
||||||
|
/** Host name n8n can be reached */
|
||||||
|
@Env('N8N_HOST')
|
||||||
|
readonly host: string = 'localhost';
|
||||||
|
|
||||||
|
/** HTTP port n8n can be reached */
|
||||||
|
@Env('N8N_PORT')
|
||||||
|
readonly port: number = 5678;
|
||||||
|
|
||||||
|
/** IP address n8n should listen on */
|
||||||
|
@Env('N8N_LISTEN_ADDRESS')
|
||||||
|
readonly listen_address: string = '0.0.0.0';
|
||||||
|
|
||||||
|
/** HTTP Protocol via which n8n can be reached */
|
||||||
|
@Env('N8N_PROTOCOL')
|
||||||
|
readonly protocol: 'http' | 'https' = 'http';
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ describe('GlobalConfig', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultConfig: GlobalConfig = {
|
const defaultConfig: GlobalConfig = {
|
||||||
|
path: '/',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 5678,
|
||||||
|
listen_address: '0.0.0.0',
|
||||||
|
protocol: 'http',
|
||||||
database: {
|
database: {
|
||||||
logging: {
|
logging: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { Logger } from '@/Logger';
|
||||||
import { ServiceUnavailableError } from './errors/response-errors/service-unavailable.error';
|
import { ServiceUnavailableError } from './errors/response-errors/service-unavailable.error';
|
||||||
import { OnShutdown } from '@/decorators/OnShutdown';
|
import { OnShutdown } from '@/decorators/OnShutdown';
|
||||||
import { ActiveWebhooks } from '@/ActiveWebhooks';
|
import { ActiveWebhooks } from '@/ActiveWebhooks';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export abstract class AbstractServer {
|
export abstract class AbstractServer {
|
||||||
|
@ -33,7 +34,7 @@ export abstract class AbstractServer {
|
||||||
|
|
||||||
protected externalHooks: ExternalHooks;
|
protected externalHooks: ExternalHooks;
|
||||||
|
|
||||||
protected protocol = config.getEnv('protocol');
|
protected protocol = Container.get(GlobalConfig).protocol;
|
||||||
|
|
||||||
protected sslKey: string;
|
protected sslKey: string;
|
||||||
|
|
||||||
|
@ -149,25 +150,24 @@ export abstract class AbstractServer {
|
||||||
this.server = http.createServer(app);
|
this.server = http.createServer(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PORT = config.getEnv('port');
|
const { port, listen_address: address } = Container.get(GlobalConfig);
|
||||||
const ADDRESS = config.getEnv('listen_address');
|
|
||||||
|
|
||||||
this.server.on('error', (error: Error & { code: string }) => {
|
this.server.on('error', (error: Error & { code: string }) => {
|
||||||
if (error.code === 'EADDRINUSE') {
|
if (error.code === 'EADDRINUSE') {
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
`n8n's port ${PORT} is already in use. Do you have another instance of n8n running already?`,
|
`n8n's port ${port} is already in use. Do you have another instance of n8n running already?`,
|
||||||
);
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await new Promise<void>((resolve) => this.server.listen(PORT, ADDRESS, () => resolve()));
|
await new Promise<void>((resolve) => this.server.listen(port, address, () => resolve()));
|
||||||
|
|
||||||
this.externalHooks = Container.get(ExternalHooks);
|
this.externalHooks = Container.get(ExternalHooks);
|
||||||
|
|
||||||
await this.setupHealthCheck();
|
await this.setupHealthCheck();
|
||||||
|
|
||||||
this.logger.info(`n8n ready on ${ADDRESS}, port ${PORT}`);
|
this.logger.info(`n8n ready on ${address}, port ${port}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
|
|
@ -10,8 +10,6 @@ import type { HttpError } from 'express-openapi-validator/dist/framework/types';
|
||||||
import type { OpenAPIV3 } from 'openapi-types';
|
import type { OpenAPIV3 } from 'openapi-types';
|
||||||
import type { JsonObject } from 'swagger-ui-express';
|
import type { JsonObject } from 'swagger-ui-express';
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { UserRepository } from '@db/repositories/user.repository';
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
import { UrlService } from '@/services/url.service';
|
import { UrlService } from '@/services/url.service';
|
||||||
|
@ -25,7 +23,7 @@ async function createApiRouter(
|
||||||
handlersDirectory: string,
|
handlersDirectory: string,
|
||||||
publicApiEndpoint: string,
|
publicApiEndpoint: string,
|
||||||
): Promise<Router> {
|
): Promise<Router> {
|
||||||
const n8nPath = config.getEnv('path');
|
const n8nPath = Container.get(GlobalConfig).path;
|
||||||
const swaggerDocument = YAML.load(openApiSpecPath) as JsonObject;
|
const swaggerDocument = YAML.load(openApiSpecPath) as JsonObject;
|
||||||
// add the server depending on the config so the user can interact with the API
|
// add the server depending on the config so the user can interact with the API
|
||||||
// from the Swagger UI
|
// from the Swagger UI
|
||||||
|
|
|
@ -124,7 +124,7 @@ export class Start extends BaseCommand {
|
||||||
|
|
||||||
private async generateStaticAssets() {
|
private async generateStaticAssets() {
|
||||||
// Read the index file and replace the path placeholder
|
// Read the index file and replace the path placeholder
|
||||||
const n8nPath = config.getEnv('path');
|
const n8nPath = Container.get(GlobalConfig).path;
|
||||||
const restEndpoint = config.getEnv('endpoints.rest');
|
const restEndpoint = config.getEnv('endpoints.rest');
|
||||||
const hooksUrls = config.getEnv('externalFrontendHooksUrls');
|
const hooksUrls = config.getEnv('externalFrontendHooksUrls');
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ export class Start extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { default: localtunnel } = await import('@n8n/localtunnel');
|
const { default: localtunnel } = await import('@n8n/localtunnel');
|
||||||
const port = config.getEnv('port');
|
const { port } = Container.get(GlobalConfig);
|
||||||
|
|
||||||
const webhookTunnel = await localtunnel(port, {
|
const webhookTunnel = await localtunnel(port, {
|
||||||
host: 'https://hooks.n8n.cloud',
|
host: 'https://hooks.n8n.cloud',
|
||||||
|
|
|
@ -307,40 +307,6 @@ export const schema = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// How n8n can be reached (Editor & REST-API)
|
|
||||||
path: {
|
|
||||||
format: String,
|
|
||||||
default: '/',
|
|
||||||
arg: 'path',
|
|
||||||
env: 'N8N_PATH',
|
|
||||||
doc: 'Path n8n is deployed to',
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
format: String,
|
|
||||||
default: 'localhost',
|
|
||||||
arg: 'host',
|
|
||||||
env: 'N8N_HOST',
|
|
||||||
doc: 'Host name n8n can be reached',
|
|
||||||
},
|
|
||||||
port: {
|
|
||||||
format: Number,
|
|
||||||
default: 5678,
|
|
||||||
arg: 'port',
|
|
||||||
env: 'N8N_PORT',
|
|
||||||
doc: 'HTTP port n8n can be reached',
|
|
||||||
},
|
|
||||||
listen_address: {
|
|
||||||
format: String,
|
|
||||||
default: '0.0.0.0',
|
|
||||||
env: 'N8N_LISTEN_ADDRESS',
|
|
||||||
doc: 'IP address n8n should listen on',
|
|
||||||
},
|
|
||||||
protocol: {
|
|
||||||
format: ['http', 'https'] as const,
|
|
||||||
default: 'http',
|
|
||||||
env: 'N8N_PROTOCOL',
|
|
||||||
doc: 'HTTP Protocol via which n8n can be reached',
|
|
||||||
},
|
|
||||||
secure_cookie: {
|
secure_cookie: {
|
||||||
doc: 'This sets the `Secure` flag on n8n auth cookie',
|
doc: 'This sets the `Secure` flag on n8n auth cookie',
|
||||||
format: Boolean,
|
format: Boolean,
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class UrlService {
|
export class UrlService {
|
||||||
/** Returns the base URL n8n is reachable from */
|
/** Returns the base URL n8n is reachable from */
|
||||||
readonly baseUrl: string;
|
readonly baseUrl: string;
|
||||||
|
|
||||||
constructor() {
|
constructor(private readonly globalConfig: GlobalConfig) {
|
||||||
this.baseUrl = this.generateBaseUrl();
|
this.baseUrl = this.generateBaseUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +28,7 @@ export class UrlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateBaseUrl(): string {
|
private generateBaseUrl(): string {
|
||||||
const protocol = config.getEnv('protocol');
|
const { path, port, host, protocol } = this.globalConfig;
|
||||||
const host = config.getEnv('host');
|
|
||||||
const port = config.getEnv('port');
|
|
||||||
const path = config.getEnv('path');
|
|
||||||
|
|
||||||
if ((protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)) {
|
if ((protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)) {
|
||||||
return `${protocol}://${host}${path}`;
|
return `${protocol}://${host}${path}`;
|
||||||
|
|
|
@ -6,11 +6,19 @@ import { UserService } from '@/services/user.service';
|
||||||
import { UrlService } from '@/services/url.service';
|
import { UrlService } from '@/services/url.service';
|
||||||
import { mockInstance } from '../../shared/mocking';
|
import { mockInstance } from '../../shared/mocking';
|
||||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
|
||||||
describe('UserService', () => {
|
describe('UserService', () => {
|
||||||
const urlService = new UrlService();
|
const globalConfig = mockInstance(GlobalConfig, {
|
||||||
|
host: 'localhost',
|
||||||
|
path: '/',
|
||||||
|
port: 5678,
|
||||||
|
listen_address: '0.0.0.0',
|
||||||
|
protocol: 'http',
|
||||||
|
});
|
||||||
|
const urlService = new UrlService(globalConfig);
|
||||||
const userRepository = mockInstance(UserRepository);
|
const userRepository = mockInstance(UserRepository);
|
||||||
const userService = new UserService(mock(), userRepository, mock(), urlService);
|
const userService = new UserService(mock(), userRepository, mock(), urlService, mock());
|
||||||
|
|
||||||
const commonMockUser = Object.assign(new User(), {
|
const commonMockUser = Object.assign(new User(), {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
|
|
Loading…
Reference in a new issue