Mailnib docs v1.0.0

Configure

Configuration

Outcome: you know what every line in .env.example does and which ones you must set.

Mailnib reads its settings from environment variables. On cPanel they live in a .env file next to app.js (copy .env.example to start). On Render and Vercel you enter them in the dashboard. Restart the app after changing any of them.

Required means the app will not work correctly without it in production. Optional means the default is fine for most sites.

Core

VariableRequiredWhat it does
DATABASE_URLRequiredThe PostgreSQL connection string, postgresql://USER:PASSWORD@HOST:5432/DATABASE. Percent-encode special characters in the password. Add ?sslmode=require for most hosted databases.
APP_KEYRequiredA random secret of at least 32 characters. The web installer generates it. Change it only by rotating it, see Security checks and rotating APP_KEY; the example value in .env.example is refused as too weak.
PUBLIC_APP_URLRequiredThe address your customers use, with https://, such as https://mail.example.com. Confirmation links, export links and exported image addresses are built from it. Publishing to email platforms needs it to be a public https:// address.
APP_KEY_PREVIOUSOptionalOnly while rotating APP_KEY: the old key. Values sealed with either key are readable until pnpm app-key:rotate has run. Remove it afterwards.
TRUSTED_PROXY_HOPSOptionalHow many proxies in front of the app append to X-Forwarded-For, for request limits. Default 1; use 2 behind a CDN.
RATE_LIMITINGOptionaloff disables every request limit. For automated tests only. Default on.
CRON_SECRETOptionalA long random secret that lets your scheduler call POST /api/jobs/dunning to send failed-payment reminders. Without it the endpoint answers "not found". See Payment providers.
MIGRATE_ON_STARTOptionaltrue applies pending database migrations every time the app starts. Set it to true on cPanel and Render. Default false.
REGISTRATION_DISABLEDOptionaltrue closes the public sign-up page; existing customers still sign in, and you can still create tenants from the console. Default false.
MARKETING_SITE_ENABLEDOptionalfalse turns the public storefront off: / opens the app and the pricing, templates and contact pages answer "not found". Legal pages stay online. Default true. See Your public site and legal pages.

Storage

Uploaded images and exported files are kept on the local disk unless you configure a bucket.

VariableRequiredWhat it does
STORAGE_DRIVEROptionallocal (default) or s3. Required as s3 on Vercel.
STORAGE_ROOTOptionalThe folder for local storage, relative to the app or absolute. Default storage. Render sets /var/data. The installer's token and progress files also live here.
STORAGE_S3_BUCKETWith S3The bucket name. When set, uploads go to the bucket.
STORAGE_S3_REGIONWith S3The bucket's region, such as eu-west-1.
STORAGE_S3_ENDPOINTOptionalLeave empty for Amazon S3. Set it for Cloudflare R2, Backblaze B2, MinIO and other S3-compatible services.
AWS_ACCESS_KEY_IDWith S3Access key with read and write access to the bucket.
AWS_SECRET_ACCESS_KEYWith S3Its secret.

Transactional mail

These are the fallbacks for Email (SMTP) settings. Anything you save in the operator console wins over them, except the password.

VariableRequiredWhat it does
MAIL_TRANSPORTOptionalLeave empty and the platform chooses: SMTP in production once an SMTP host is set (here or in the console), the log otherwise. smtp forces SMTP. log writes every message to the server log and delivers nothing, even when SMTP settings are saved.
SMTP_HOSTWith SMTPYour provider's SMTP host, such as smtp.postmarkapp.com.
SMTP_PORTOptionalDefault 587. Use 465 for implicit TLS.
SMTP_ENCRYPTIONOptionalstarttls (default, port 587), tls (port 465) or none.
SMTP_USERNAMEWith SMTPUsually your full address or an API user.
SMTP_PASSWORDWith SMTPWhen set, it wins over a password saved in the console. Setting it here keeps the password out of the database, which we recommend.
MAIL_FROM_NAMEOptionalThe sender name customers see. Default Mailnib.
MAIL_FROM_ADDRESSWith SMTPThe sender address. It must be on a domain your provider allows.
MAIL_REPLY_TOOptionalWhere replies go.

Template sample photos

VariableRequiredWhat it does
SAMPLE_IMAGES_URLOptionalDefaults to https://assets.keyngdev.online, the author's sample-photo host, when unset or empty. Set a different HTTP(S) base URL to use your own host, or off to show drawn placeholders. The host contains sample photos and thumbnails/<template-id>.png. Photos are hosted remotely and are not part of the download. Unreachable photos and thumbnails fall back to the bundled artwork.

Generate hosted thumbnails

Run pnpm templates:hosted-thumbnails --out /absolute/path/outside-the-repository after building the packages. It renders every built-in template with the configured sample photos. Upload the resulting PNG files to the thumbnails/ folder on the same host. Keep these files outside the repository and the downloadable release: they contain hosted photos. The command rejects output inside the repository, including paths through symlinks, and stops if a sample photo cannot be downloaded.

Payment providers

All optional. Each provider needs every one of its variables; see Payment providers.

VariableWhat it does
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRETStripe secret key (sk_…) and the signing secret of your webhook endpoint (whsec_…).
PAYPAL_CLIENT_ID, PAYPAL_SECRET, PAYPAL_WEBHOOK_IDPayPal REST app credentials and the ID of the webhook you create for it.
RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRETRazorpay API keys and webhook secret.
PAYSTACK_SECRET_KEYPaystack secret key; it also verifies webhooks.
STRIPE_API_URL, PAYPAL_API_URL, RAZORPAY_API_URL, PAYSTACK_API_URLOverride the provider's API address. Leave them out of .env entirely (an empty value is not the same as unset); they exist for testing and for PayPal's sandbox.

Web installer

VariableRequiredWhat it does
INSTALL_STATE_DIROptionalWhere the installer keeps its token, progress and the "installed" marker. Defaults to STORAGE_ROOT. It must survive restarts and must not be inside a public folder.

The installer also honours INSTALL_ENV_FILE, the file it appends APP_KEY to (default: .env in the app folder). You rarely need it.

First operator from the command line

Used only by pnpm db:seed, which Vercel's build runs. The web installer ignores them.

VariableWhat it does
OPERATOR_EMAILThe operator's sign-in address. Default operator@example.com.
OPERATOR_NAMEThe operator's display name.
OPERATOR_PASSWORDAt least 12 characters. When empty, a random password is printed once. It is only used when the operator is first created.

Demo mode

Never turn these on for a real installation. See Demo mode.

VariableWhat it does
DEMO_MODEtrue turns the installation into a public demo with one-click sign-in and guarded settings. Default false.
DEMO_RESET_TOKENSecret for the reset endpoint. Without it, the endpoint answers 404.
DEMO_RESET_INTERVAL_MINUTESOnly used to tell visitors when the next reset is due. Default 60.
DEMO_PURCHASE_URLYour item page. When set, the demo's landing page shows a Buy a licence button.

Set by the host

You normally leave these alone; Node.js or your host provides them.

VariableWhat it does
NODE_ENVproduction on a live site.
PORTThe port the app listens on. cPanel and Render set it. Default 3000.
HOSTNAME, HOSTThe address the server binds to. Default 0.0.0.0.
NEXT_RUNTIMESet by the framework. Do not change it.
VERCELSet by Vercel. Its presence makes S3 storage mandatory.

Development only

VariableWhat it does
SCREENSHOT_MODEFixture mode used when capturing screenshots. Keep 0.
NEXT_DIST_DIRA second build folder used by the test tools. Leave empty.

Storage settings reference

Local files are stored under STORAGE_ROOT. To use Amazon S3, Cloudflare R2, Backblaze B2 or another compatible service, set the S3 environment variables listed above and restart. Storage settings are read-only in the console; its connection test checks the configured adapter. Storage is counted per workspace as files arrive. After restoring a database and files together, check the usage totals.

Scheduled work

Set CRON_SECRET and schedule a daily GET or POST to /api/jobs/dunning with Authorization: Bearer <CRON_SECRET>. Vercel uses the schedule in apps/web/vercel.json; on other hosts, configure the scheduler provided by your host. Keep the secret out of public commands and logs. Ordinary deferred work still runs inline without a scheduler.

Mailnib 1.0.0 · These pages open from your download with no server and no internet connection.