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
+23
-10
@@ -70,17 +70,28 @@ Cloudflare token, or you can add them by hand later.
|
||||
|
||||
## Step 2 — Create the application in Coolify
|
||||
|
||||
1. **New Resource → Docker Compose**, pointed at this repository.
|
||||
1. **New Resource → Docker Compose**, pointed at this repository. It lives on
|
||||
Gitea: choose **Private Repository (with Deploy Key)** and use
|
||||
`git@git.lucasrguerra.dev.br:lucasrguerra/LambdaMail.git` with a key that is
|
||||
registered in Gitea. An application that was created from a GitHub source
|
||||
keeps cloning from GitHub until its source is changed in the Coolify UI; the
|
||||
API cannot change it.
|
||||
2. Coolify will read `docker-compose.yaml`. Leave the compose file alone; all
|
||||
configuration is environment.
|
||||
3. Under **Environment Variables**, paste the contents of
|
||||
`.env.production.example` and replace every value marked `CHANGE`.
|
||||
3. Create the environment on your own machine, then paste it into
|
||||
**Environment Variables**:
|
||||
|
||||
Generate each secret separately:
|
||||
```bash
|
||||
scripts/init-env.sh --production # writes .env with random secrets
|
||||
```
|
||||
|
||||
```bash
|
||||
openssl rand -base64 36
|
||||
```
|
||||
The script lists every value that is still at a development default
|
||||
(`MAIL_DOMAIN`, `PRIMARY_MAIL_HOST`, `WEBMAIL_HOST`, `PUBLIC_IPV4`,
|
||||
`IMAGE_TAG`); set those in `.env`, then paste. Every variable is explained
|
||||
inline in [`.env.example`](../.env.example).
|
||||
|
||||
`POSTGRES_PASSWORD` and `REDIS_PASSWORD` are generated as hex on purpose: they
|
||||
go inside connection URIs, and the `/` and `+` of base64 break them.
|
||||
|
||||
`LAMBDAMAIL_MASTER_KEY` deserves particular care. It encrypts every DKIM
|
||||
private key, TOTP secret and provider token in the database. **Store a copy
|
||||
@@ -176,8 +187,9 @@ have propagated and the IP has some sending history.
|
||||
|
||||
## Upgrading
|
||||
|
||||
Images are published to the Gitea container registry for `linux/amd64` and `linux/arm64` on every merge
|
||||
to `main`.
|
||||
Images are published to the Gitea container registry for `linux/amd64` and
|
||||
`linux/arm64` on every merge to `main`, and again under the version number when
|
||||
a `v*` tag is pushed (see [RELEASING.md](RELEASING.md)).
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
@@ -189,7 +201,8 @@ Deploys pull the images CI published rather than building on the server;
|
||||
source instead.
|
||||
|
||||
Migrations run automatically on start, before the services that depend on them.
|
||||
**Pin `IMAGE_TAG` to a `sha-` tag rather than leaving it on `latest`.** Not
|
||||
**Pin `IMAGE_TAG` to a release (`1.0.0`) or a `sha-` tag rather than leaving it
|
||||
on `latest`.** Not
|
||||
only for rollback: `docker compose up` does not re-pull a tag it already has
|
||||
locally, so a deployment left on `latest` will happily keep running the image
|
||||
it pulled the first time while reporting success. An immutable tag changes on
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# Releasing LambdaMail
|
||||
|
||||
How a version gets from a commit to a server, and what runs where. The history
|
||||
of what changed is in the [CHANGELOG](../CHANGELOG.md).
|
||||
|
||||
## The pipeline
|
||||
|
||||
Everything runs on **Gitea Actions** (`.gitea/workflows/`), on runners hosted on
|
||||
the Oracle server.
|
||||
|
||||
| Workflow | Runs on | Does |
|
||||
| :--- | :--- | :--- |
|
||||
| `ci.yml` | every push and pull request | language lint, Go and TypeScript suites against a real Postgres, webmail tests, a Trivy scan of the repository and of each image, and the whole stack brought up with compose |
|
||||
| `release.yml` | a push to `main`, a `v*` tag, or by hand | runs `ci.yml` again, builds the six images for `linux/amd64` and `linux/arm64`, publishes them, and on a tag creates the release |
|
||||
|
||||
Nothing is published unless the full suite passes first.
|
||||
|
||||
Images go to the Gitea registry, one package per service:
|
||||
|
||||
```
|
||||
git.lucasrguerra.dev.br/lucasrguerra/lambdamail/{protocols,auth,storage,webmail,migrations,rspamd}
|
||||
```
|
||||
|
||||
Tags on every image: `latest`, `sha-<full commit>`, and on a version tag also
|
||||
`1.2.3`, `1.2` and `1`. The packages are public, so a server pulls them without
|
||||
logging in.
|
||||
|
||||
## Cutting a release
|
||||
|
||||
1. Update [CHANGELOG.md](../CHANGELOG.md) and [CHANGELOG.pt-BR.md](../CHANGELOG.pt-BR.md):
|
||||
move what is under *Unreleased* to a new `## [X.Y.Z] - date` section.
|
||||
2. Set `"version"` in `services/{auth,storage,webmail}/package.json` and their
|
||||
lockfiles to the same number.
|
||||
3. Merge to `main` and wait for the `Release` run of that merge to go green.
|
||||
4. Tag the merge commit and push the tag:
|
||||
|
||||
```bash
|
||||
git tag -a v1.2.3 -m "LambdaMail 1.2.3"
|
||||
git push gitea v1.2.3
|
||||
```
|
||||
|
||||
The tag triggers `release.yml` once more. It republishes the images under
|
||||
`1.2.3`, `1.2` and `1` (layers are cached, so this is quick) and creates the
|
||||
entry under **Releases** with the image list and the commit log since the
|
||||
previous tag. A tag with a hyphen (`v1.3.0-rc.1`) is marked as a pre-release.
|
||||
|
||||
Versions follow [Semantic Versioning](https://semver.org/): a change to a
|
||||
migration, a required environment variable, or a published port is at least a
|
||||
minor release, and anything that needs manual steps on upgrade is called out in
|
||||
the changelog.
|
||||
|
||||
## Deploying a version
|
||||
|
||||
Coolify pulls; it does not build. See the *Upgrading* section of
|
||||
[DEPLOYMENT.md](DEPLOYMENT.md) for the two-step deploy (set `IMAGE_TAG`, then
|
||||
deploy). In short:
|
||||
|
||||
1. `IMAGE_TAG` = the release (`1.2.3`) or `sha-<commit>`. Never `latest`.
|
||||
2. Deploy. Migrations run before the services that need them.
|
||||
3. Check `GET /health` on `protocols` and sign in to the webmail.
|
||||
|
||||
To roll back, set `IMAGE_TAG` back to the previous release and deploy again.
|
||||
Migrations are not reverted: write them so the previous version still runs
|
||||
against the new schema.
|
||||
|
||||
## Runners
|
||||
|
||||
Two `act_runner` instances run on the Oracle server (Ampere ARM, 4 cores), each
|
||||
with its own Docker-in-Docker daemon, so two jobs never share a network or a
|
||||
port. The jobs run unprivileged.
|
||||
|
||||
- `linux/arm64` images build natively; `linux/amd64` images build under QEMU
|
||||
emulation, which is slower. Layers are cached in the registry.
|
||||
- The Docker daemon of each runner keeps its layer cache between runs, and the
|
||||
toolcache volume keeps downloaded toolchains.
|
||||
- The workspace of a job is not visible to the Docker daemon, so workflows copy
|
||||
files into containers with `docker cp` instead of mounting them with `-v`.
|
||||
- Windows and macOS jobs cannot run here.
|
||||
|
||||
## Why some actions are not used
|
||||
|
||||
- `aquasecurity/trivy-action` clones Trivy from the workflow's own server,
|
||||
which is Gitea; Trivy runs from its official image instead.
|
||||
- `actions/upload-artifact` v4+ and the `gha` build cache are GitHub services;
|
||||
per-architecture images are told apart by tag, and the cache lives in the
|
||||
registry.
|
||||
- Workflows read `GITHUB_OUTPUT` and `GITHUB_STEP_SUMMARY` under those names:
|
||||
the `GITEA_*` equivalents are not set by the runner.
|
||||
Reference in new issue
Block a user