CI / Lint de idioma (R9) (push) Successful in 5s
CI / Go (protocols) (push) Successful in 2m34s
CI / TypeScript (storage) (push) Successful in 15s
CI / Testes (webmail) (push) Successful in 51s
CI / TypeScript (auth) (push) Successful in 2m39s
CI / Trivy (dependências, segredos e Dockerfiles) (push) Successful in 9s
CI / Imagem (migrations) (push) Successful in 5s
CI / Stack completa (push) Successful in 1m11s
CI / Imagem (auth) (push) Successful in 17s
CI / Imagem (protocols) (push) Successful in 7s
CI / Imagem (rspamd) (push) Successful in 5s
CI / Imagem (storage) (push) Successful in 17s
CI / Imagem (webmail) (push) Successful in 1m52s
- CHANGELOG.md and CHANGELOG.pt-BR.md, from the project history. - .env.example now serves development and production; scripts/init-env.sh (make env) creates .env with random secrets. .env.production.example is gone. - docs/RELEASING.md: the pipeline, how a version is cut and deployed, the runners. - DEPLOYMENT.md and both READMEs updated for Gitea and the new env flow. - Service versions set to 1.0.0. - CI: the proxy network step is idempotent and the stack is torn down always, since the runner's Docker daemon now outlives a job. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
133 lines
6.1 KiB
Bash
133 lines
6.1 KiB
Bash
# LambdaMail - environment
|
|
#
|
|
# One file for local development and for production.
|
|
#
|
|
# scripts/init-env.sh copy this to .env and generate the secrets
|
|
# scripts/init-env.sh --production the same, plus a list of what you still
|
|
# have to set before this is a real server
|
|
#
|
|
# Values below are the local-development defaults. Lines marked PRODUCTION say
|
|
# what a real deployment needs. In Coolify, paste the finished .env into the
|
|
# environment editor instead of keeping a file on the host.
|
|
#
|
|
# The secrets are left empty on purpose. The script fills them with random
|
|
# values, and compose refuses to start while one is empty, because a default
|
|
# secret in a published repository is not a secret.
|
|
|
|
# --- Container images -------------------------------------------------------
|
|
# Published to the Gitea registry by .gitea/workflows/release.yml for
|
|
# linux/amd64 and linux/arm64. The deploy host pulls instead of compiling:
|
|
# `docker compose pull && docker compose up -d`. `make up` builds from source
|
|
# through the build overlay and ignores these.
|
|
# PRODUCTION: pin IMAGE_TAG to a release (1.0.0) or to a sha-<commit> tag. Never
|
|
# leave `latest` on a server: a redeploy then silently changes what runs.
|
|
IMAGE_NAMESPACE=git.lucasrguerra.dev.br/lucasrguerra/lambdamail
|
|
IMAGE_TAG=latest
|
|
|
|
# --- Identity ---------------------------------------------------------------
|
|
# MAIL_DOMAIN is the domain you send and receive as.
|
|
# PRIMARY_MAIL_HOST is the host the MX record points at; its PTR must match it.
|
|
# PRODUCTION: MAIL_DOMAIN=example.com PRIMARY_MAIL_HOST=mail.example.com
|
|
# WEBMAIL_HOST=mail.example.com PUBLIC_IPV4=<the VPS public IPv4>
|
|
MAIL_DOMAIN=localhost
|
|
PRIMARY_MAIL_HOST=mail.localhost
|
|
WEBMAIL_HOST=localhost:3000
|
|
# Optional separate host for /admin.
|
|
ADMIN_HOST=
|
|
PUBLIC_IPV4=127.0.0.1
|
|
# Leave empty unless IPv6 has a matching PTR and is covered by SPF. A half
|
|
# configured IPv6 is a common cause of rejection (PLAN.md premises).
|
|
PUBLIC_IPV6=
|
|
|
|
# --- Secrets ----------------------------------------------------------------
|
|
# Filled in by scripts/init-env.sh. To do it by hand:
|
|
#
|
|
# POSTGRES_PASSWORD, REDIS_PASSWORD openssl rand -hex 24
|
|
# JWT_SECRET, LAMBDAMAIL_MASTER_KEY openssl rand -hex 32
|
|
#
|
|
# The first two are substituted into connection URIs (postgres://user:PASS@db/...
|
|
# and redis://:PASS@redis:6379), so they must hold no character that means
|
|
# something in a URL: use hex, NOT `openssl rand -base64`, whose alphabet has "/"
|
|
# and "+". A "/" ends the authority component, the host is parsed as part of the
|
|
# password and every connection fails authentication - which shows up as the
|
|
# migrations container exiting 1 while Postgres itself reports healthy.
|
|
POSTGRES_DB=lambdamail
|
|
POSTGRES_USER=lambdamail
|
|
POSTGRES_PASSWORD=
|
|
REDIS_PASSWORD=
|
|
# Signs webmail and admin sessions. At least 32 characters; the auth service
|
|
# refuses to start below that.
|
|
JWT_SECRET=
|
|
# Encrypts DKIM private keys, TOTP secrets and provider tokens at rest.
|
|
# LOSING THIS MAKES EVERY STORED SECRET UNRECOVERABLE: back it up separately
|
|
# from the database (PLAN.md risk R9).
|
|
LAMBDAMAIL_MASTER_KEY=
|
|
|
|
# --- DNS automation (Cloudflare) --------------------------------------------
|
|
# The token needs Zone.DNS:Edit plus Zone.Zone:Read on the zone. Leave it empty
|
|
# to manage the records by hand; the service then logs that DNS sync is off.
|
|
CLOUDFLARE_API_TOKEN=
|
|
DNS_SYNC_INTERVAL_SECONDS=21600
|
|
|
|
# --- TLS --------------------------------------------------------------------
|
|
# traefik: read the certificate the proxy already manages (default; DANE is not
|
|
# possible in this mode).
|
|
# acme: obtain the certificate here via DNS-01. Required for DANE, because
|
|
# only this mode can reuse a pre-generated key.
|
|
TLS_MODE=traefik
|
|
# Used only when TLS_MODE=acme. Leave ACME_DIRECTORY_URL empty for Let's Encrypt
|
|
# production; point it at the staging directory while testing, since production
|
|
# rate limits can lock a domain out for a week.
|
|
ACME_EMAIL=
|
|
ACME_DIRECTORY_URL=
|
|
# Where the proxy keeps its certificates, and the Docker network it listens on.
|
|
# PRODUCTION (Coolify): COOLIFY_PROXY_DIR=/data/coolify/proxy
|
|
COOLIFY_PROXY_DIR=./local/acme
|
|
COOLIFY_PROXY_NETWORK=coolify
|
|
TRAEFIK_ACME_FILENAME=acme.json
|
|
CERT_POLL_INTERVAL_SECONDS=60
|
|
# Static certificate files, used when no ACME store is available (local dev;
|
|
# `make gen-dev-cert` writes them).
|
|
PROTOCOLS_CERT_PATH=/etc/lambdamail/certs/cert.pem
|
|
PROTOCOLS_KEY_PATH=/etc/lambdamail/certs/key.pem
|
|
PROTOCOLS_SPOOL_DIR=/var/lambdamail/spool
|
|
|
|
# --- Transport security -----------------------------------------------------
|
|
# Start at "testing": senders honour the policy but do not hard-fail on it.
|
|
# Promote to "enforce" only once TLS-RPT reports come back clean; enforce with a
|
|
# broken certificate silently blackholes inbound mail.
|
|
MTA_STS_MODE=testing
|
|
OUTBOUND_MTA_STS_ENABLED=true
|
|
# DANE stays off unless TLS_MODE=acme. Under proxy-managed certificates the key
|
|
# changes at every renewal and the published TLSA record stops matching, which
|
|
# permanently rejects mail at every validating MTA (PLAN.md section 5.1).
|
|
OUTBOUND_DANE_ENABLED=false
|
|
DNSSEC_RESOLVER=1.1.1.1:53
|
|
MAX_MESSAGE_BYTES=52428800
|
|
# ARC seals accepted messages so a downstream receiver can still tell that the
|
|
# mail authenticated at the first hop. Only worth enabling on a host that
|
|
# forwards mail onward.
|
|
ARC_SEAL_ENABLED=false
|
|
|
|
# --- Smarthost (hosts where outbound port 25 is blocked) --------------------
|
|
# Most VPS providers block port 25. If `make preflight` reports it blocked, set a
|
|
# relay here: all delivery goes through it and it is added to the published SPF,
|
|
# without which every relayed message fails SPF.
|
|
RELAY_HOST=
|
|
RELAY_PORT=587
|
|
RELAY_USER=
|
|
RELAY_PASS=
|
|
# The SPF term that authorises the relay, exactly as the provider documents it.
|
|
# It cannot be derived from RELAY_HOST, and getting it wrong is worse than
|
|
# leaving it out. Brevo's relay is smtp-relay.brevo.com, but brevo.com publishes
|
|
# the SPF of their corporate mail: the sending ranges are at spf.brevo.com, so
|
|
# the value there is "include:spf.brevo.com".
|
|
RELAY_SPF_INCLUDE=
|
|
|
|
# --- Storage ----------------------------------------------------------------
|
|
STORAGE_DRIVER=local
|
|
S3_ENDPOINT=
|
|
S3_BUCKET=
|
|
S3_ACCESS_KEY=
|
|
S3_SECRET_KEY=
|