Skip to the text
tidy notebookDocs GitHub

Hosting a server

View as Markdown

Configuration reference

This page is for the person who runs the server. It names every setting of the server and of its Compose file, and states what each one does.

Self-hosting is the installation guide, and it explains when you need a setting. This page is the list to look a name up in.

Where a setting lives

  • .env holds the nonsecret settings. Copy .env.example, which states an example value for each line, and change the values.
  • The secret directory, NOTESAPP_SECRETS_DIR, holds one file for each secret. A secret never goes in .env.
  • A platform that mounts no file, such as a platform that gives a service variables only, sets each secret in its variable instead of its file. Each secret has a variable and a _FILE variable. Set one of the two, never both. With Compose, use the file.
  • The accounts page of the application holds the mail server, the two legal documents and who can make an account, unless the environment names them. See Accounts and invitations.

An empty value is a value that is not set. A setting applies at the next start:

Shell
docker compose up -d

A server that cannot use a value does not start. Its log names the setting and the form that it needs.

The address of the installation

Setting What it does
NOTESAPP_ORIGIN Required. The public address of the installation, with its scheme, for example https://notes.example.com. Cookies and every full address belong to it.
NOTESAPP_ADDITIONAL_ORIGINS More addresses that reach this installation, separated by commas. Write each one in full, with the scheme of NOTESAPP_ORIGIN. Empty serves NOTESAPP_ORIGIN alone.
NOTESAPP_PUBLISHED_ORIGIN The address that shows published pages and nothing else, on a host name of its own. Open sign-up does not need it. Empty shows published pages on NOTESAPP_ORIGIN.
NOTESAPP_BIND_HOST The address of the host where Compose publishes the application. Keep the loopback address behind a reverse proxy.
NOTESAPP_PORT In .env, the port of the host where Compose publishes the application. Inside the container the server always listens on port 3000. Without Compose, it is the port that the server listens on, and an origin with a port requires it.
NOTESAPP_TRUSTED_PROXIES The proxies whose forwarded headers the server believes: an address, a range in CIDR form, or loopback, linklocal or uniquelocal, separated by commas. Empty believes none. See Behind a reverse proxy.

The TLS profile

These settings apply only when you start the optional Caddy proxy with docker compose --profile tls up -d.

Setting What it does
NOTESAPP_DOMAIN The domain that Caddy answers and gets a certificate for. Empty answers localhost with a certificate that only serves a local check.
NOTESAPP_PUBLISHED_DOMAIN The host name of NOTESAPP_PUBLISHED_ORIGIN, which Caddy answers too.
NOTESAPP_TLS_DIR The host directory where Caddy keeps the certificates and their private keys. Put it on encrypted storage.

Data, secrets and the image

Setting What it does
NOTESAPP_DATABASE_DIR Required. The host directory of the PostgreSQL data.
NOTESAPP_STORAGE_DIR Required. The host directory of the images and files of the notes. It must belong to uid 10001, the user of the image.
NOTESAPP_SECRETS_DIR Required. The host directory of the secret files below. Keep it outside the repository.
POSTGRES_USER The administrator of the database that Compose starts.
POSTGRES_DB The name of the database.
NOTESAPP_IMAGE The name and the tag of the application image that Compose runs, for example a release from the registry.
COMPOSE_FILE The Compose files that docker compose reads, separated by colons. Add the mail file or the legal file below to use them.

The secret directory holds these files. Each one has mode 0600 and belongs to uid 10001. Self-hosting states the content of each one and a command that writes them.

  • postgres_password, migration_database_url, runtime_database_password, auth_database_password, runtime_database_url, auth_database_url and auth_secret, for every installation.
  • smtp_password, with docker/compose.mail.yaml.
  • smtp_url, with docker/compose.mail-url.yaml.
  • s3_access_key_id and s3_secret_access_key, with docker/compose.s3.yaml.

Object storage

The server keeps the images of the notes, an upload that waits for its note, and an import that arrives in parts in an object store. To use an S3 compatible store, add docker/compose.s3.yaml to COMPOSE_FILE, then set these values. See Object storage.

Setting What it does
NOTESAPP_OBJECT_STORE filesystem, the default, keeps everything in the storage directory. s3 uses an S3 compatible store. docker/compose.s3.yaml sets it.
NOTESAPP_S3_BUCKET The bucket of the store.
NOTESAPP_S3_REGION The region of the bucket, for example auto for Cloudflare R2 or us-east-1 for AWS.
NOTESAPP_S3_ENDPOINT The address of the store, for example the address of R2 or of a MinIO server. Empty uses AWS itself.
NOTESAPP_S3_ACCESS_KEY_ID The access key ID, on a platform that mounts no file. Compose reads it from the s3_access_key_id file.
NOTESAPP_S3_ACCESS_KEY_ID_FILE The file that holds the access key ID, from s3_access_key_id. Compose sets it.
NOTESAPP_S3_SECRET_ACCESS_KEY The secret access key, on a platform that mounts no file. Compose reads it from the s3_secret_access_key file.
NOTESAPP_S3_SECRET_ACCESS_KEY_FILE The file that holds the secret access key, from s3_secret_access_key. Compose sets it.

Requests and limits

Setting What it does
NOTESAPP_LOG_LEVEL Required without Compose. How much the server logs: fatal, error, warn, info, debug or silent.
NOTESAPP_MAX_BODY_BYTES Required without Compose. The largest body of a request, in bytes. An image upload and a workspace import have bounds of their own, which this value does not change.
NOTESAPP_MAX_HEADER_BYTES Required without Compose. The largest headers of one request, in bytes.
NOTESAPP_REQUEST_TIMEOUT_MS Required without Compose. The time in which a whole request must arrive, in milliseconds. It includes the body of an upload on a slow link.
NOTESAPP_UPLOAD_IDLE_TIMEOUT_MS The longest pause between two parts of an upload, in milliseconds. It must be shorter than the request timeout.
NOTESAPP_RATE_LIMIT_WINDOW_S The window of the attempt limit, in seconds. The limit counts the attempts of one client at the screens and actions that a stranger can reach, such as setup, sign-in and sign-up.
NOTESAPP_RATE_LIMIT_MAX How many attempts one client makes in one window.
NOTESAPP_SESSION_MAX_AGE_S How long a session that nobody uses lasts, in seconds. A browser that uses its session keeps it longer, so a person who works every day stays signed in.

Stopping the server

Setting What it does
NOTESAPP_SHUTDOWN_GRACE_MS The time between the moment the server says that it is not ready and the moment it stops taking requests, in milliseconds. 0 suits an installation with no proxy.
NOTESAPP_SHUTDOWN_DEADLINE_MS The whole time of a stop before the server ends at once, in milliseconds. It must be longer than the grace.

See Stopping the server.

Accounts

Setting What it does
NOTESAPP_ACCOUNT_LIMIT_BYTES The storage limit that a new account starts with, in bytes. An administrator changes the limit of one account.
NOTESAPP_INVITATION_LIFETIME_HOURS How long a new invitation works, in hours.
NOTESAPP_PENDING_ACCOUNT_HOURS How long a sign-up waits for the person to open the link in its message, in hours.
NOTESAPP_SIGNUP_DIFFICULTY How hard the check of the browser is at a sign-up, from 8 to 28. Each step doubles the time that it takes.
NOTESAPP_BREACH_CHECK on checks a new password against the range service of Have I Been Pwned. off suits a server with no outbound network.
NOTESAPP_NEW_ACCOUNT_STANDING active or locked, the standing that a new account starts with. Empty is active, so a new account uses every operation, as before. A locked account signs in to one screen and can only export its notes, delete itself, or open billing. The first account is always active.
NOTESAPP_NEW_ACCOUNT_REMOVE_AFTER How long a new locked account lives before the daily run removes it, as a number of days and d, for example 30d. It needs NOTESAPP_NEW_ACCOUNT_STANDING set to locked. Empty sets no removal time.
NOTESAPP_REGISTRATION_POLICY Who can make an account: invitation or open. A value here wins over the accounts page, which then offers no change. The server writes it at each start. open needs a mail server and both legal documents in the environment too, or the server does not start. Empty leaves the choice to an administrator, who keeps the last policy that the environment named.

The operator API

A service of the operator, such as a billing service, can read and set the controls of an account with one secret. With no setting, the operator API is off and the installation sends nothing anywhere.

Setting What it does
NOTESAPP_OPERATOR_TOKEN The one secret of the operator API, of at least 32 characters with no space. A service sends it as a bearer token to the operations under /api/operator/. These operations answer on any host name, so a service on a private network can reach them. Set it here on a platform that mounts no file, or set the file below. Empty in both turns the operator API off, and each of its operations answers that it is off.
NOTESAPP_OPERATOR_TOKEN_FILE The file that holds that secret. Use it with Compose.
NOTESAPP_ACCOUNT_PORTAL_URL The full address of the account portal of that service, with no query, for example https://billing.example.com. The application calls it Billing. Every account opens it from the Billing section of Settings, and a locked account opens it to unlock itself. A page or a message of the portal can send a person back to /portal?path=<path> of the application, for example /portal?path=/account. The application signs the person in first when needed, then opens that path of the portal. A path that the portal cannot take opens the root of the portal. The server adds a single-use token that works for 60 seconds, and the portal gives the token back to the operator API to learn the account. The portal needs the operator API, so set its secret too, or the server does not start. Empty shows no portal.

Limits of each month

The server counts, for each calendar month in UTC, the bytes that the published pages send, the bytes that each account downloads, and each write and read call to an S3 store. An administrator or the operator API can give one account a published transfer limit and a download limit. The settings below are caps for the whole installation. A count stays in the memory of the server for at most 10 seconds, so two servers can pass a cap by the traffic of 10 seconds. Each cap holds until the first day of the next month. With no cap and no limit of an account, the server refuses nothing.

Setting What it does
NOTESAPP_PUBLISHED_TRANSFER_CAP_BYTES The most bytes that all published pages send in one month. Past it, each published link shows a page that says that the link opens nothing. Empty sets no cap.
NOTESAPP_DOWNLOAD_CAP_BYTES The most bytes that all accounts download in one month. Past it, an export, an image and the first copy of the notes on a new device wait for the next month. The rest of the application still works. Empty sets no cap.
NOTESAPP_OBJECT_WRITE_CAP The most write calls to the S3 store in one month: a write, a copy, a part of an upload and a list. Past it, an image upload and a workspace import wait for the next month. The file store of the storage directory makes no call, so this cap holds an S3 store only. Empty sets no cap.
NOTESAPP_OBJECT_READ_CAP The most read calls to the S3 store in one month. Past it, an image does not load, and a published page shows no image. This cap holds an S3 store only. Empty sets no cap.

Mail

The mail server sends invitations, the links of a sign-up and the links of a password reset. You can set it on the accounts page instead. A mail server in the environment wins, and the page then offers no change. See Mail.

To name it in the environment, add docker/compose.mail.yaml to COMPOSE_FILE, then set these values. The Compose file passes them only with that file.

Setting What it does
NOTESAPP_SMTP_HOST The host name of the mail server, with no scheme and no port.
NOTESAPP_SMTP_PORT The port of the mail server.
NOTESAPP_SMTP_SECURITY tls speaks TLS from the start, starttls switches to TLS before the password, none uses no TLS.
NOTESAPP_SMTP_USERNAME The user name of the mail server. This file requires it, and a user name needs a password.
NOTESAPP_SMTP_PASSWORD The password of the mail server. Compose reads it from the smtp_password file.
NOTESAPP_SMTP_PASSWORD_FILE The file that holds the password. Compose sets it.
NOTESAPP_MAIL_FROM The sender, an address that the mail server lets you send from, with a name or without one.

A mail server that takes mail with no sign-in, such as a relay inside your network, is named as one address instead, with docker/compose.mail-url.yaml. Use the fields or the address, never both.

Setting What it does
NOTESAPP_SMTP_URL The mail server as one smtp or smtps address. It needs the sender.
NOTESAPP_SMTP_URL_FILE The file that holds that address. Compose sets it.

A public installation names its terms and its privacy notice. You can write both on the accounts page instead. Documents in the environment win, and the page then offers no change. Name both documents or neither. Each one has a version and one source: an address on another site, or a Markdown file that the server shows. See Open sign-up.

Setting What it does
NOTESAPP_TERMS_URL The address of the terms on another site.
NOTESAPP_TERMS_FILE The Markdown file of the terms that the server shows. docker/compose.legal.yaml sets it.
NOTESAPP_TERMS_VERSION The version of the terms. A new version asks every person to accept the terms again.
NOTESAPP_PRIVACY_URL The address of the privacy notice on another site.
NOTESAPP_PRIVACY_FILE The Markdown file of the privacy notice that the server shows. docker/compose.legal.yaml sets it.
NOTESAPP_PRIVACY_VERSION The version of the privacy notice.
NOTESAPP_LEGAL_DIR The host directory that holds terms.md and privacy.md, which docker/compose.legal.yaml gives the server.

Logs

Setting What it does
NOTESAPP_LOG_MAX_SIZE The size at which Docker starts a new log file of a container.
NOTESAPP_LOG_MAX_FILE How many log files of each container Docker keeps.

See Logs.

The migration

The migrate command of the image applies the migrations and stops. It reads three secrets and no setting of the server, and the serve command reads none of them. See Migrate and serve as two steps. Each secret comes from its variable or from its file, never both. When neither is set, the command reads the file that Compose puts in the container.

Setting What it does
NOTESAPP_MIGRATION_DATABASE_URL The database address of the administrator or of the migration role.
NOTESAPP_MIGRATION_DATABASE_URL_FILE The file that holds that address. Empty reads migration_database_url.
NOTESAPP_RUNTIME_PASSWORD The password that the migration gives notesapp_app, of at least 12 characters.
NOTESAPP_RUNTIME_PASSWORD_FILE The file that holds that password. Empty reads runtime_database_password.
NOTESAPP_AUTH_PASSWORD The password that the migration gives notesapp_auth. It must differ from the other one.
NOTESAPP_AUTH_PASSWORD_FILE The file that holds that password. Empty reads auth_database_password.

Settings that the Compose file sets

Do not set these in .env. The Compose file and the image set them, and they matter only when you run the server without Compose.

Setting What it does
NOTESAPP_HOST The address that the server listens on inside the container.
NOTESAPP_STORAGE_ROOT The directory of the images and files of the notes inside the container.
NOTESAPP_DATABASE_URL The database address of the application.
NOTESAPP_DATABASE_URL_FILE The file that holds that address, from runtime_database_url.
NOTESAPP_AUTH_DATABASE_URL The database address of the sign-in service, which must differ from the address above.
NOTESAPP_AUTH_DATABASE_URL_FILE The file that holds that address, from auth_database_url.
NOTESAPP_AUTH_SECRET The secret that signs the sessions, from 32 to 512 characters.
NOTESAPP_AUTH_SECRET_FILE The file that holds the secret, from auth_secret.

A value and its file are never set together. A server that finds both does not start.