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 <git@herrmehren.de>
This commit is contained in:
David Mehren 2023-03-25 16:19:31 +01:00 committed by Tilman Vatteroth
parent 55f3bd9b60
commit f7f052fca1
6 changed files with 65 additions and 54 deletions

View file

@ -28,7 +28,7 @@ describe('appConfig', () => {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
HD_RENDERER_BASE_URL: rendererBaseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
HD_PERSIST_INTERVAL: '100', HD_PERSIST_INTERVAL: '100',
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
@ -51,7 +51,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
HD_PERSIST_INTERVAL: '100', HD_PERSIST_INTERVAL: '100',
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
@ -98,7 +98,7 @@ describe('appConfig', () => {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
HD_RENDERER_BASE_URL: rendererBaseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_PERSIST_INTERVAL: '100', HD_PERSIST_INTERVAL: '100',
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -122,7 +122,7 @@ describe('appConfig', () => {
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
HD_RENDERER_BASE_URL: rendererBaseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl,
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
{ {
@ -145,7 +145,7 @@ describe('appConfig', () => {
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
HD_RENDERER_BASE_URL: rendererBaseUrl, HD_RENDERER_BASE_URL: rendererBaseUrl,
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_PERSIST_INTERVAL: '0', HD_PERSIST_INTERVAL: '0',
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -168,7 +168,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: invalidBaseUrl, HD_BASE_URL: invalidBaseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -203,24 +203,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: negativePort.toString(), HD_BACKEND_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_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -229,7 +212,26 @@ describe('appConfig', () => {
}, },
); );
expect(() => appConfig()).toThrow( 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(); restore();
}); });
@ -239,7 +241,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: floatPort.toString(), HD_BACKEND_PORT: floatPort.toString(),
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -247,7 +249,7 @@ describe('appConfig', () => {
clear: true, clear: true,
}, },
); );
expect(() => appConfig()).toThrow('"PORT" must be an integer'); expect(() => appConfig()).toThrow('"HD_BACKEND_PORT" must be an integer');
restore(); restore();
}); });
@ -256,7 +258,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: invalidPort, HD_BACKEND_PORT: invalidPort,
HD_LOGLEVEL: loglevel, HD_LOGLEVEL: loglevel,
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -264,7 +266,7 @@ describe('appConfig', () => {
clear: true, clear: true,
}, },
); );
expect(() => appConfig()).toThrow('"PORT" must be a number'); expect(() => appConfig()).toThrow('"HD_BACKEND_PORT" must be a number');
restore(); restore();
}); });
@ -273,7 +275,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_LOGLEVEL: invalidLoglevel, HD_LOGLEVEL: invalidLoglevel,
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
}, },
@ -290,7 +292,7 @@ describe('appConfig', () => {
{ {
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
HD_BASE_URL: baseUrl, HD_BASE_URL: baseUrl,
PORT: port.toString(), HD_BACKEND_PORT: port.toString(),
HD_LOGLEVEL: invalidLoglevel, HD_LOGLEVEL: invalidLoglevel,
HD_PERSIST_INTERVAL: invalidPersistInterval.toString(), HD_PERSIST_INTERVAL: invalidPersistInterval.toString(),
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */

View file

@ -55,7 +55,7 @@ const schema = Joi.object({
.default(3000) .default(3000)
.max(65535) .max(65535)
.optional() .optional()
.label('PORT'), .label('HD_BACKEND_PORT'),
loglevel: Joi.string() loglevel: Joi.string()
.valid(...Object.values(Loglevel)) .valid(...Object.values(Loglevel))
.default(Loglevel.WARN) .default(Loglevel.WARN)
@ -79,7 +79,7 @@ export default registerAs('appConfig', () => {
{ {
baseUrl: process.env.HD_BASE_URL, baseUrl: process.env.HD_BASE_URL,
rendererBaseUrl: process.env.HD_RENDERER_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, loglevel: process.env.HD_LOGLEVEL,
persistInterval: process.env.HD_PERSIST_INTERVAL, persistInterval: process.env.HD_PERSIST_INTERVAL,
}, },

View file

@ -4,7 +4,7 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
# #
:8080 {$HD_BASE_URL}
log { log {
output stdout output stdout
@ -12,9 +12,9 @@ log {
format console format console
} }
reverse_proxy /realtime http://127.0.0.1:3000 reverse_proxy /realtime http://127.0.0.1:{$HD_BACKEND_PORT:3000}
reverse_proxy /api/* http://127.0.0.1:3000 reverse_proxy /api/* http://127.0.0.1:{$HD_BACKEND_PORT:3000}
reverse_proxy /public/* http://127.0.0.1:3000 reverse_proxy /public/* http://127.0.0.1:{$HD_BACKEND_PORT:3000}
reverse_proxy /uploads/* http://127.0.0.1:3000 reverse_proxy /uploads/* http://127.0.0.1:{$HD_BACKEND_PORT:3000}
reverse_proxy /apidoc/* http://127.0.0.1:3000 reverse_proxy /apidoc/* http://127.0.0.1:{$HD_BACKEND_PORT:3000}
reverse_proxy /* http://127.0.0.1:3001 reverse_proxy /* http://127.0.0.1:{$HD_FRONTEND_PORT:3001}

View file

@ -1,4 +1,4 @@
# Base settings # General settings
HD_BASE_URL="https://hedgedoc2.localhost" HD_BASE_URL="https://hedgedoc2.localhost"
HD_SESSION_SECRET="session_secret" HD_SESSION_SECRET="session_secret"

View file

@ -2,27 +2,33 @@ HedgeDoc can be configured via environment variables either directly or via an `
## The `.env` file ## 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 ```ini
HD_BASE_URL="http://localhost" HD_BASE_URL="http://localhost:8080"
HD_MEDIA_BACKEND="filesystem" HD_SESSION_SECRET="session_secret"
HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH="uploads/"
HD_DATABASE_TYPE="sqlite" HD_DATABASE_TYPE="sqlite"
HD_DATABASE_NAME="./hedgedoc.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 !!! 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 ## General
| environment variable | default | example | description | | environment variable | default | example | description |
|--------------------------|------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| |--------------------------|------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| `HD_BASE_URL` | - | `https://md.example.com` | The URL 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 |
| `PORT` | 3000 | | The port the HedgeDoc instance runs on. | | `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_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_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. | | `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? ### 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 ## Notes

View file

@ -12,11 +12,11 @@
"format:fix": "prettier -w \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"", "format:fix": "prettier -w \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"",
"lint": "eslint --max-warnings=0 --ext .ts,.tsx src", "lint": "eslint --max-warnings=0 --ext .ts,.tsx src",
"lint:fix": "eslint --fix --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:ci": "cross-env PORT=3001 NODE_ENV=test next start",
"start:dev": "cross-env PORT=3001 next dev", "start:dev": "cross-env PORT=${HD_FRONTEND_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: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=3001 NODE_ENV=test NEXT_PUBLIC_TEST_MODE=true 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:open": "cypress open",
"test:e2e": "cypress run --browser chrome", "test:e2e": "cypress run --browser chrome",
"test:e2e:ci": "cypress run --browser chrome --record true --parallel --group \"chrome\"", "test:e2e:ci": "cypress run --browser chrome --record true --parallel --group \"chrome\"",