From f7f052fca195d4775c6da2673eaeec92b702f874 Mon Sep 17 00:00:00 2001 From: David Mehren Date: Sat, 25 Mar 2023 16:19:31 +0100 Subject: [PATCH] refactor: use separate env vars for frontend/backend port As we moved to a combined .env file for simplicity, frontend and backend need to be configured with separate variables. Signed-off-by: David Mehren --- backend/src/config/app.config.spec.ts | 64 ++++++++++++++------------- backend/src/config/app.config.ts | 4 +- dev-reverse-proxy/Caddyfile | 14 +++--- docker/.env | 2 +- docs/content/config/index.md | 27 +++++++---- frontend/package.json | 8 ++-- 6 files changed, 65 insertions(+), 54 deletions(-) diff --git a/backend/src/config/app.config.spec.ts b/backend/src/config/app.config.spec.ts index 1ca04e061..ff70781f7 100644 --- a/backend/src/config/app.config.spec.ts +++ b/backend/src/config/app.config.spec.ts @@ -28,7 +28,7 @@ describe('appConfig', () => { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_LOGLEVEL: loglevel, HD_PERSIST_INTERVAL: '100', /* eslint-enable @typescript-eslint/naming-convention */ @@ -51,7 +51,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_LOGLEVEL: loglevel, HD_PERSIST_INTERVAL: '100', /* eslint-enable @typescript-eslint/naming-convention */ @@ -98,7 +98,7 @@ describe('appConfig', () => { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_PERSIST_INTERVAL: '100', /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -122,7 +122,7 @@ describe('appConfig', () => { HD_BASE_URL: baseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl, HD_LOGLEVEL: loglevel, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), /* eslint-enable @typescript-eslint/naming-convention */ }, { @@ -145,7 +145,7 @@ describe('appConfig', () => { HD_BASE_URL: baseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl, HD_LOGLEVEL: loglevel, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_PERSIST_INTERVAL: '0', /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -168,7 +168,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: invalidBaseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_LOGLEVEL: loglevel, /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -203,24 +203,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: negativePort.toString(), - HD_LOGLEVEL: loglevel, - /* eslint-enable @typescript-eslint/naming-convention */ - }, - { - clear: true, - }, - ); - expect(() => appConfig()).toThrow('"PORT" must be a positive number'); - restore(); - }); - - it('when given a out-of-range PORT', async () => { - const restore = mockedEnv( - { - /* eslint-disable @typescript-eslint/naming-convention */ - HD_BASE_URL: baseUrl, - PORT: outOfRangePort.toString(), + HD_BACKEND_PORT: negativePort.toString(), HD_LOGLEVEL: loglevel, /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -229,7 +212,26 @@ describe('appConfig', () => { }, ); expect(() => appConfig()).toThrow( - '"PORT" must be less than or equal to 65535', + '"HD_BACKEND_PORT" must be a positive number', + ); + restore(); + }); + + it('when given a out-of-range PORT', async () => { + const restore = mockedEnv( + { + /* eslint-disable @typescript-eslint/naming-convention */ + HD_BASE_URL: baseUrl, + HD_BACKEND_PORT: outOfRangePort.toString(), + HD_LOGLEVEL: loglevel, + /* eslint-enable @typescript-eslint/naming-convention */ + }, + { + clear: true, + }, + ); + expect(() => appConfig()).toThrow( + '"HD_BACKEND_PORT" must be less than or equal to 65535', ); restore(); }); @@ -239,7 +241,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: floatPort.toString(), + HD_BACKEND_PORT: floatPort.toString(), HD_LOGLEVEL: loglevel, /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -247,7 +249,7 @@ describe('appConfig', () => { clear: true, }, ); - expect(() => appConfig()).toThrow('"PORT" must be an integer'); + expect(() => appConfig()).toThrow('"HD_BACKEND_PORT" must be an integer'); restore(); }); @@ -256,7 +258,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: invalidPort, + HD_BACKEND_PORT: invalidPort, HD_LOGLEVEL: loglevel, /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -264,7 +266,7 @@ describe('appConfig', () => { clear: true, }, ); - expect(() => appConfig()).toThrow('"PORT" must be a number'); + expect(() => appConfig()).toThrow('"HD_BACKEND_PORT" must be a number'); restore(); }); @@ -273,7 +275,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_LOGLEVEL: invalidLoglevel, /* eslint-enable @typescript-eslint/naming-convention */ }, @@ -290,7 +292,7 @@ describe('appConfig', () => { { /* eslint-disable @typescript-eslint/naming-convention */ HD_BASE_URL: baseUrl, - PORT: port.toString(), + HD_BACKEND_PORT: port.toString(), HD_LOGLEVEL: invalidLoglevel, HD_PERSIST_INTERVAL: invalidPersistInterval.toString(), /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/backend/src/config/app.config.ts b/backend/src/config/app.config.ts index 2d546bbc7..961eec60a 100644 --- a/backend/src/config/app.config.ts +++ b/backend/src/config/app.config.ts @@ -55,7 +55,7 @@ const schema = Joi.object({ .default(3000) .max(65535) .optional() - .label('PORT'), + .label('HD_BACKEND_PORT'), loglevel: Joi.string() .valid(...Object.values(Loglevel)) .default(Loglevel.WARN) @@ -79,7 +79,7 @@ export default registerAs('appConfig', () => { { baseUrl: process.env.HD_BASE_URL, rendererBaseUrl: process.env.HD_RENDERER_BASE_URL, - port: parseOptionalNumber(process.env.PORT), + port: parseOptionalNumber(process.env.HD_BACKEND_PORT), loglevel: process.env.HD_LOGLEVEL, persistInterval: process.env.HD_PERSIST_INTERVAL, }, diff --git a/dev-reverse-proxy/Caddyfile b/dev-reverse-proxy/Caddyfile index 57f78361f..2325360e7 100644 --- a/dev-reverse-proxy/Caddyfile +++ b/dev-reverse-proxy/Caddyfile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: AGPL-3.0-only # -:8080 +{$HD_BASE_URL} log { output stdout @@ -12,9 +12,9 @@ log { format console } -reverse_proxy /realtime http://127.0.0.1:3000 -reverse_proxy /api/* http://127.0.0.1:3000 -reverse_proxy /public/* http://127.0.0.1:3000 -reverse_proxy /uploads/* http://127.0.0.1:3000 -reverse_proxy /apidoc/* http://127.0.0.1:3000 -reverse_proxy /* http://127.0.0.1:3001 +reverse_proxy /realtime http://127.0.0.1:{$HD_BACKEND_PORT:3000} +reverse_proxy /api/* http://127.0.0.1:{$HD_BACKEND_PORT:3000} +reverse_proxy /public/* http://127.0.0.1:{$HD_BACKEND_PORT:3000} +reverse_proxy /uploads/* http://127.0.0.1:{$HD_BACKEND_PORT:3000} +reverse_proxy /apidoc/* http://127.0.0.1:{$HD_BACKEND_PORT:3000} +reverse_proxy /* http://127.0.0.1:{$HD_FRONTEND_PORT:3001} diff --git a/docker/.env b/docker/.env index 6d037950e..004b4d85c 100644 --- a/docker/.env +++ b/docker/.env @@ -1,4 +1,4 @@ -# Base settings +# General settings HD_BASE_URL="https://hedgedoc2.localhost" HD_SESSION_SECRET="session_secret" diff --git a/docs/content/config/index.md b/docs/content/config/index.md index 21eb8a351..448723450 100644 --- a/docs/content/config/index.md +++ b/docs/content/config/index.md @@ -2,27 +2,33 @@ HedgeDoc can be configured via environment variables either directly or via an ` ## The `.env` file -The `.env` file should be placed in the root of the project and contains key-value pairs of environment variables and their corresponding value. This can for example look like this: +The `.env` file should be placed in the root of the project and contains key-value pairs of +environment variables and their corresponding value. This can for example look like this: ```ini -HD_BASE_URL="http://localhost" -HD_MEDIA_BACKEND="filesystem" -HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH="uploads/" +HD_BASE_URL="http://localhost:8080" +HD_SESSION_SECRET="session_secret" HD_DATABASE_TYPE="sqlite" HD_DATABASE_NAME="./hedgedoc.sqlite" +HD_MEDIA_BACKEND="filesystem" +HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH="uploads/" ``` -We also provide an `.env.example` file containing a minimal configuration in the root of the project. This should help you to write your own configuration. +We also provide an `.env.example` file containing a minimal configuration in the root of the project. +This should help you to write your own configuration. !!! warning - The minimal configuration provided in `.env.example` is exactly that: minimal. It will let you start HedgeDoc, but it is **not** meant to be used in production without prior changes. + The minimal configuration provided in `.env.example` is exactly that: minimal. + It will let you start HedgeDoc for local development, + but it is **not** meant to be used in production without prior changes. ## General | environment variable | default | example | description | |--------------------------|------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| -| `HD_BASE_URL` | - | `https://md.example.com` | The URL the HedgeDoc instance runs on. | -| `PORT` | 3000 | | The port the HedgeDoc instance runs on. | +| `HD_BASE_URL` | - | `https://md.example.com` | The URL the HedgeDoc instance is accessed with, like it is entered in the browser | +| `HD_BACKEND_PORT` | 3000 | | The port the backend process listens on. | +| `HD_FRONTEND_PORT` | 3001 | | The port the frontend process listens on. | | `HD_RENDERER_BASE_URL` | Content of HD_BASE_URL | | The URL the renderer runs on. If omitted this will be the same as `HD_BASE_URL`. | | `HD_LOGLEVEL` | warn | | The loglevel that should be used. Options are `error`, `warn`, `info`, `debug` or `trace`. | | `HD_FORBIDDEN_NOTE_IDS` | - | `notAllowed,alsoNotAllowed` | A list of note ids (separated by `,`), that are not allowed to be created or requested by anyone. | @@ -31,7 +37,10 @@ We also provide an `.env.example` file containing a minimal configuration in the ### Why should I want to run my renderer on a different (sub-)domain? -If the renderer is provided by another domain, it's way harder to manipulate HedgeDoc or steal credentials from the rendered note content, because renderer and editor are more isolated. This increases the security of the software and greatly mitigates [XSS attacks](https://en.wikipedia.org/wiki/Cross-site_scripting). However, you can run HedgeDoc without this extra security, but we recommend using it if possible. +If the renderer is provided by another domain, it's way harder to manipulate HedgeDoc or +steal credentials from the rendered note content, because renderer and editor are more isolated. +This increases the security of the software and greatly mitigates [XSS attacks](https://en.wikipedia.org/wiki/Cross-site_scripting). +However, you can run HedgeDoc without this extra security, but we recommend using it if possible. ## Notes diff --git a/frontend/package.json b/frontend/package.json index 816699c8c..9093b9c12 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,11 +12,11 @@ "format:fix": "prettier -w \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"", "lint": "eslint --max-warnings=0 --ext .ts,.tsx src", "lint:fix": "eslint --fix --ext .ts,.tsx src", - "start": "cross-env PORT=3001 next start", + "start": "cross-env PORT=${HD_FRONTEND_PORT:-3001} next start", "start:ci": "cross-env PORT=3001 NODE_ENV=test next start", - "start:dev": "cross-env PORT=3001 next dev", - "start:dev:mock": "cross-env PORT=3001 NEXT_PUBLIC_USE_MOCK_API=true HD_BASE_URL=\"http://localhost:3001/\" HD_RENDERER_BASE_URL=\"http://127.0.0.1:3001/\" next dev", - "start:dev:test": "cross-env PORT=3001 NODE_ENV=test NEXT_PUBLIC_TEST_MODE=true next dev", + "start:dev": "cross-env PORT=${HD_FRONTEND_PORT:-3001} next dev", + "start:dev:mock": "cross-env PORT=${HD_FRONTEND_PORT:-3001} NEXT_PUBLIC_USE_MOCK_API=true HD_BASE_URL=\"http://localhost:3001/\" HD_RENDERER_BASE_URL=\"http://127.0.0.1:3001/\" next dev", + "start:dev:test": "cross-env PORT=${HD_FRONTEND_PORT:-3001} NODE_ENV=test NEXT_PUBLIC_TEST_MODE=true next dev", "test:e2e:open": "cypress open", "test:e2e": "cypress run --browser chrome", "test:e2e:ci": "cypress run --browser chrome --record true --parallel --group \"chrome\"",