Skip to content

Configuration

Environment files, migrations and the node ace CLI all belong to apps/webapp — that is where a .env goes, not the repository root. Start from .env.example:

bash
cp apps/webapp/.env.example apps/webapp/.env

Required variables

VariableNotes
NODE_ENVdevelopment, production, or test
PORTPort the application listens on, e.g. 3333
APP_KEYApplication secret key — generate with openssl rand -base64 32
HOSTIP address or hostname, e.g. 0.0.0.0 or localhost
LOG_LEVELe.g. info, debug
APP_URLPublic application URL, e.g. https://your-domain.com
DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_DATABASEPostgreSQL connection
LIMITER_STOREWhere the /api/v1/* rate limiter keeps its counters — database or memory

Optional variables

VariableNotes
SESSION_DRIVERdatabase, cookie, or memory; defaults to database
TZTimezone, e.g. UTC
ALLOW_REGISTRATIONWhether the instance accepts sign-ups — see Authentication
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETGoogle sign-in — see Authentication
SMTP_* / MAIL_FROM_*Outgoing mail — see below

Google sign-in

To obtain a Client ID and Secret:

  1. Open the Google Cloud Console and create or select a project.
  2. Enable the OAuth 2.0 API.
  3. Configure the OAuth consent screen if you have not already.
  4. Under Credentials, create an OAuth 2.0 Client ID of type Web application.
  5. Add an authorized redirect URI: http://localhost:3333/auth/callback for development, or https://your-domain.com/auth/callback in production.
  6. Set the resulting Client ID and Secret as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.

Leave both empty to run without Google sign-in. Setting only one of the two is rejected at boot.

Outgoing mail

Email is optional. Leave every SMTP_* and MAIL_* variable empty and the instance runs without it — the behaviors below are simply unavailable, and account recovery goes through the node ace user:* commands instead (see Console commands).

Setting any one of them commits you to a complete configuration: SMTP_HOST and MAIL_FROM_ADDRESS are then both required, and a partial configuration is rejected at boot rather than silently dropping the one email a locked-out user is waiting for.

VariableNotes
SMTP_HOSTRelay hostname
SMTP_PORTDefaults to 587
SMTP_USERNAMEOptional, but requires SMTP_PASSWORD when set
SMTP_PASSWORDOptional, but requires SMTP_USERNAME when set
SMTP_SECUREImplicit TLS. Defaults to true on port 465, false elsewhere
MAIL_FROM_ADDRESSSender address
MAIL_FROM_NAMESender name, defaults to MyLinks

What outgoing mail changes

Four behaviors switch on or off depending on whether mail is configured:

BehaviorWithout outgoing mailWith outgoing mail
Signing in with a passwordNo confirmation requiredA confirmed address is required; the login page offers to resend the link
/forgot-passwordUnavailable — reset with node ace user:reset-passwordSends a self-service reset link
Changing your email addressUnavailable from the settings page — use node ace user:*Two-party confirmation: new address confirms, old address is notified
Admin-issued password resetConsole only: node ace user:reset-password --linkThe admin area can email the reset link directly

In development

dev.compose.yml ships mailpit: point SMTP_HOST at 127.0.0.1 and SMTP_PORT at 1025, then read everything the app sends on http://localhost:8025. Nothing leaves your machine.

In production

An external SMTP provider is the recommended path. The repository's compose.yml does carry a local boky/postfix relay behind an opt-in profile:

bash
docker compose --profile smtp up -d

with SMTP_ALLOWED_SENDER_DOMAINS set to the domains it may send for, SMTP_RELAYHOST set if it should forward to an upstream, and the app configured with SMTP_HOST=smtp and SMTP_PORT=587.

Be aware of what self-hosting a mail transfer agent involves: without SPF, DKIM, DMARC records and a matching reverse DNS entry, Gmail and Outlook drop the mail, and many hosting providers block outbound port 25 outright.

Released under the GPLv3 License.