Files
TA-Deployment-Broker/docs/deployment.md
T
2026-07-26 14:15:24 -05:00

172 lines
5.8 KiB
Markdown

# Single-VM deployment
The deployment is relocatable. Compose paths and management commands are
resolved relative to the repository checkout, so it can live anywhere on the
VM. `/opt/idssys/TA-Deployment-Access` is only one possible example.
It consists of four containers:
- TAPM broker, with an embedded SQLite database
- Gitea, with its own embedded SQLite database and repository storage
- Nginx, terminating TLS for the broker and Gitea
- Certbot, run on demand for certificate issuance and renewal
Only the configured Nginx HTTP/HTTPS ports and Gitea SSH port are published.
They default to 8680, 8643, and 2222. Inside Docker, Nginx continues to listen
on ports 80 and 443. The broker and Gitea HTTP services are reachable only on
the private `tapm-edge` Docker network.
## 1. VM and network
Install Docker Engine with Compose v2. Permit the selected HTTP, HTTPS, and SSH
ports and forward public TCP 80, 443, and the selected SSH port from the
datacenter edge to them. Create public DNS A/AAAA records for both application
names before requesting the certificate.
Public port 80 must reach the container's port 80 for HTTP-01 certificate
renewal. For example, if `HTTP_PORT=8080`, the edge must forward public port 80
to VM port 8080. If IPv6 is published, it must reach this same VM.
## 2. Install the repository
```sh
sudo mkdir -p /YOUR/INSTALL/PARENT
sudo git clone GITEA-REPOSITORY-URL /YOUR/INSTALL/PARENT/TA-Deployment-Access
sudo chown -R 1000:1000 /YOUR/INSTALL/PARENT/TA-Deployment-Access
cd /YOUR/INSTALL/PARENT/TA-Deployment-Access
cp .env.example .env
chmod 600 .env
```
Set `BROKER_DOMAIN`, `GITEA_DOMAIN`, and `LETSENCRYPT_EMAIL` first. `HTTP_PORT`
and `HTTPS_PORT` control the VM-side Docker bindings and default to 8680 and
8643. The datacenter edge should therefore forward public ports 80 and 443 to
VM ports 8680 and 8643. Replace all example domains in the TAPM variables.
Generate the cookie secret with:
```sh
openssl rand -base64 48
```
Runtime state is deliberately visible below the checkout:
```text
config/
├── broker/ # tapm.db and SQLite WAL files
├── gitea/
│ ├── config/ # app.ini and Gitea configuration
│ └── data/ # repositories, packages, and gitea.db
├── letsencrypt/ # account data, certificate, and private key
├── ssl/ # optional administrator-provided certificate
├── certbot-webroot/ # HTTP-01 challenge files
└── backups/ # local offline snapshots
```
The contents are ignored by Git. They must never be committed.
## 3. Bootstrap Gitea and TLS
```sh
./manage.sh bootstrap
```
This prepares the runtime directories, creates the private Docker network,
starts Gitea and the HTTP-only Nginx configuration, obtains a certificate when
using Let's Encrypt, and switches Nginx to TLS.
For an administrator-provided certificate instead, place the certificate and
key in `config/ssl/` and set:
```dotenv
SSL_MODE=custom
SSL_CERTIFICATE_DIR=./config/ssl
SSL_CERTIFICATE_FILE=fullchain.pem
SSL_CERTIFICATE_KEY_FILE=privkey.pem
```
The certificate must cover both `BROKER_DOMAIN` and `GITEA_DOMAIN`. With custom
mode, `bootstrap` skips Certbot and `renew` is intentionally unavailable;
replace the files through the certificate provider's process and restart or
reload Nginx. `SSL_CERTIFICATE_DIR` can point at another directory relative to
the repository or at an absolute host path.
Create the initial Gitea administrator:
```sh
docker compose --env-file .env -f deploy/gitea/compose.yaml exec gitea \
gitea admin user create \
--admin --username taiadmin --email ADMIN-EMAIL \
--password 'TEMPORARY-RANDOM-PASSWORD' --must-change-password
```
Sign in to Gitea at `https://GITEA_DOMAIN`, create the `TAI` organization, and
create:
1. `tapm-packages`, with a read-only package token.
2. `tapm-publisher`, with a write package token.
3. An OAuth2 application whose callback is
`https://BROKER_DOMAIN/auth/callback`.
Place those token and OAuth values in `.env`. The broker cannot start until all
required credentials are present.
## 4. Start the complete deployment
```sh
./manage.sh start
./manage.sh status
curl --fail "https://BROKER_DOMAIN/health/ready"
curl --fail "https://GITEA_DOMAIN/api/healthz"
```
The broker automatically applies SQLite schema migrations before starting.
## 5. Move repositories
For each existing repository, create an empty matching repository in the new
Gitea and mirror all refs:
```sh
git clone --mirror OLD-REPOSITORY-URL
cd REPOSITORY.git
git push --mirror ssh://git@GITEA_DOMAIN:2222/TAI/REPOSITORY.git
```
Update developer remotes, CI credentials, submodules, documentation, and the Go
module path only if the hostname embedded in the module path is also changing.
Move the deployment repository last so this checkout remains updateable during
the transition.
## 6. Renewal and backups
When `SSL_MODE=letsencrypt`, run renewal twice daily from root's crontab:
```cron
17 3,15 * * * cd /YOUR/INSTALL/PARENT/TA-Deployment-Access && ./manage.sh renew
```
Create an application-consistent local snapshot with:
```sh
./manage.sh backup
```
The backup briefly stops both SQLite writers. Copy `config/backups/` to storage
outside the VM. A backup left only on this VM does not protect against VM or
datacenter loss. Also back up `.env` through a secrets-aware system.
## 7. Updates
```sh
cd /YOUR/INSTALL/PARENT/TA-Deployment-Access
./update.sh
```
The updater operates only on the current VM. It fast-forwards the checked-out
branch, pulls the pinned Gitea image, rebuilds and restarts the local stack, and
waits for the local broker to become healthy. It has no peer discovery, SSH, or
multi-node update behavior.
Pin image versions as supplied and review release notes before changing them.
Never change Gitea between rootless and rootful image families in place.