Mailnib docs v1.0.0

Install

Install on Vercel

Outcome: Mailnib running on Vercel, with your operator account created during the build.

Vercel runs the app as serverless functions, so its file system does not keep anything between requests. Two things follow from that, and this page is built around them:

  1. Uploads must go to S3-compatible storage. The app refuses to start on Vercel without a bucket.
  2. The web installer is not used. Your operator account is created by pnpm db:seed, which vercel.json runs during every build.

Before you start

  • A PostgreSQL database reachable from the internet, such as Neon, Supabase or Vercel's own Postgres. Copy its pooled connection string.
  • An S3-compatible bucket: Amazon S3, Cloudflare R2, Backblaze B2 or similar, with an access key that can read and write it.

1. Put the source in a repository and import it

  1. On your computer, open a terminal inside the source folder of your download (the one that contains package.json), then git init, git add ., git commit -m "Mailnib" and push it to a new private repository on GitHub, GitLab or Bitbucket. Vercel builds from source, so runtime/ is not used here.
  2. In Vercel, click Add New… → Project and import that repository.
  3. Set Root Directory to apps/web and leave Include files outside the root directory switched on. Leave the framework and build settings as detected: apps/web/vercel.json sets the install command and the build command, which runs pnpm db:migrate, then pnpm db:seed, then pnpm build from the repository root.

2. Set the environment variables

Before the first deploy, open Settings → Environment Variables and add:

VariableValue
DATABASE_URLYour provider's pooled connection string.
PUBLIC_APP_URLhttps://your-project.vercel.app or your own domain.
APP_KEYA random secret of at least 32 characters. On a Mac or Linux terminal: openssl rand -base64 48
OPERATOR_EMAILThe email address you will sign in to the operator console with.
OPERATOR_PASSWORDA unique password of at least 12 characters.
STORAGE_DRIVERs3
STORAGE_S3_BUCKETYour bucket name.
STORAGE_S3_REGIONThe bucket's region, such as eu-west-1, or auto for R2.
STORAGE_S3_ENDPOINTLeave empty for Amazon S3; set it for R2, B2 or MinIO.
AWS_ACCESS_KEY_IDThe access key for the bucket.
AWS_SECRET_ACCESS_KEYIts secret.

The database must accept connections from Vercel's build machines, because migrations and the seed run during the build.

3. Deploy and check

Click Deploy. When it finishes, open https://your-address/api/health. You should see:

{"ok":true,"db":"connected","migrations":"up to date"}

Then go to https://your-address/admin/login and sign in with OPERATOR_EMAIL and OPERATOR_PASSWORD. The seed runs on every build but never changes an operator that already exists, so changing OPERATOR_PASSWORD later does not change your password.

Good to know

  • Visiting /install shows a "not found" page. That is expected: the seed recorded the installation.
  • Rate limits are kept per function instance, so they are looser than on a single server.
  • For outgoing mail, see Email (SMTP) settings.
  • Failed-payment reminders run from Vercel Cron, already set up in apps/web/vercel.json (daily, the Hobby plan limit). Set CRON_SECRET in the environment variables or the job is refused. See Payment providers.

PostgreSQL role privileges

Use a dedicated login role that owns this application's tables and functions. It needs CONNECT and CREATE on the database, USAGE and CREATE on the application schema (public), and permission to create the drizzle migration schema. Migrations need to create and alter tables, indexes, policies, triggers and functions; normal operation reads and writes those tables and executes the shipped functions. Use the same role for the installer, migrations and DATABASE_URL.

NOSUPERUSER NOBYPASSRLS is supported and recommended. Neither superuser nor BYPASSRLS nor permission to create roles is required. Tenant tables retain FORCE ROW LEVEL SECURITY even for their owner. Verified webhooks, the authenticated operator console and the secret-authenticated dunning scheduler discover workspaces through fixed, read-only functions, then enter a workspace scope for tenant data and writes. Never share the application's database credentials with tenants or browser code. Test setup creates roles to verify isolation; those privileges are needed only by the test administrator.

On managed PostgreSQL, use the database/schema owner supplied by the provider, or have the provider grant the schema creation privileges above. On cPanel, ask the host to grant these privileges if the control-panel database user cannot create schemas or functions. No elevated RLS-bypass role is needed.

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