release: 1.0.0, a changelog, one .env.example and the docs to match
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
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>
This commit is contained in:
1 parent
f500534ac6
commit
5bbbb85128
17 files changed
+524
-182
No files matched your search
+95
-44
@@ -1,81 +1,132 @@
|
||||
# --- Container images ---
|
||||
# Published to the Gitea registry by .gitea/workflows/release.yml, multi-architecture
|
||||
# (linux/amd64 and linux/arm64). The deploy host pulls these instead of
|
||||
# compiling: `docker compose pull && docker compose up -d`. Running
|
||||
# `docker compose build` locally still overrides them with a local build.
|
||||
# Pin IMAGE_TAG to a released version (e.g. 1.2.3) or a sha- tag to roll back.
|
||||
# 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
|
||||
|
||||
# --- Postgres ---
|
||||
POSTGRES_DB=lambdamail
|
||||
POSTGRES_USER=lambdamail
|
||||
POSTGRES_PASSWORD=change-me-in-local-dev
|
||||
|
||||
# --- Redis ---
|
||||
REDIS_PASSWORD=change-me-in-local-dev
|
||||
|
||||
# --- Shared secrets (local dev values — never reuse in production) ---
|
||||
JWT_SECRET=local-dev-jwt-secret-change-me-at-least-32-chars
|
||||
# Encrypts DKIM private keys and provider tokens at rest. Losing it makes every
|
||||
# stored secret unrecoverable — back it up separately from the database.
|
||||
LAMBDAMAIL_MASTER_KEY=local-dev-master-key-32-bytes-minimum-value
|
||||
|
||||
# --- Host identity ---
|
||||
PRIMARY_MAIL_HOST=mail.localhost
|
||||
# --- 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=
|
||||
|
||||
# --- DNS automation (Cloudflare) ---
|
||||
# --- 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 disable reconciliation; the service then logs that DNS sync is off.
|
||||
# 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 Traefik manages (default, DANE not possible).
|
||||
# acme: obtain the certificate ourselves via DNS-01. Required for DANE,
|
||||
# because only this mode can reuse a pre-generated key.
|
||||
# --- 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.
|
||||
# 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).
|
||||
# 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 policy ---
|
||||
# --- 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.
|
||||
# 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 Traefik-managed certificates the
|
||||
# key changes at every renewal and the published TLSA record stops matching,
|
||||
# which permanently rejects mail at every validating MTA.
|
||||
# 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 (for hosts where outbound port 25 is blocked) ---
|
||||
# Setting RELAY_HOST routes all delivery through the relay and adds it to the
|
||||
# published SPF record, without which every relayed message fails SPF.
|
||||
# --- 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=
|
||||
|
||||
# --- Webmail ---
|
||||
WEBMAIL_HOST=localhost:3000
|
||||
ADMIN_HOST=
|
||||
# --- Storage ----------------------------------------------------------------
|
||||
STORAGE_DRIVER=local
|
||||
S3_ENDPOINT=
|
||||
S3_BUCKET=
|
||||
S3_ACCESS_KEY=
|
||||
S3_SECRET_KEY=
|
||||
Reference in new issue
Block a user