This commit is contained in:
David Schroeder
2026-07-26 14:43:53 -05:00
parent 8d17c83f35
commit 890608049d
8 changed files with 89 additions and 66 deletions
+4 -1
View File
@@ -3,7 +3,10 @@ GITEA_DOMAIN=git.example.com
LETSENCRYPT_EMAIL=admin@example.com LETSENCRYPT_EMAIL=admin@example.com
HTTP_PORT=8680 HTTP_PORT=8680
HTTPS_PORT=8643 HTTPS_PORT=8643
GITEA_HTTP_PORT=3000
# Used only with compose.direct.yaml or ./manage.sh start-direct.
BROKER_DIRECT_PORT=8080
GITEA_DIRECT_PORT=3000
# letsencrypt: manage a certificate automatically with Certbot. # letsencrypt: manage a certificate automatically with Certbot.
# custom: read the named certificate files from ./config/ssl. # custom: read the named certificate files from ./config/ssl.
+4 -1
View File
@@ -15,6 +15,8 @@ The production layout is a self-contained, single-VM Docker deployment:
No external database or load balancer is required. The datacenter edge only No external database or load balancer is required. The datacenter edge only
needs to forward public TCP 80 and 443 to the configured Docker VM ports. needs to forward public TCP 80 and 443 to the configured Docker VM ports.
All services are managed by one Compose project while remaining separate
containers for independent health checks and upgrades.
See [docs/deployment.md](docs/deployment.md) for the installation, Gitea setup, See [docs/deployment.md](docs/deployment.md) for the installation, Gitea setup,
TLS bootstrap, repository move, renewal, backup, and update procedures. The TLS bootstrap, repository move, renewal, backup, and update procedures. The
@@ -25,6 +27,7 @@ ProxMenu integration contract is in [docs/client-api.md](docs/client-api.md).
```sh ```sh
GOCACHE=/tmp/tapm-go-cache go test ./... GOCACHE=/tmp/tapm-go-cache go test ./...
docker compose --env-file .env.example config docker compose --env-file .env.example config
docker compose --env-file .env.example -f deploy/gitea/compose.yaml config docker compose --env-file .env.example \
-f compose.yaml -f compose.tls.yaml -f compose.direct.yaml config
docker build -t tai/tapm-deployment-broker:local . docker build -t tai/tapm-deployment-broker:local .
``` ```
+9
View File
@@ -0,0 +1,9 @@
# Optional testing override. Do not use on an Internet-facing production VM.
services:
broker:
ports:
- "${BROKER_DIRECT_PORT:-8080}:8080"
gitea:
ports:
- "${GITEA_DIRECT_PORT:-3000}:3000"
+30
View File
@@ -28,7 +28,37 @@ services:
retries: 3 retries: 3
start_period: 15s start_period: 15s
gitea:
container_name: tapm-gitea
image: docker.gitea.com/gitea:1.26.4-rootless
env_file:
- path: .env
required: false
restart: unless-stopped
networks:
- edge
volumes:
- ./config/gitea/data:/var/lib/gitea
- ./config/gitea/config:/etc/gitea
environment:
GITEA__database__DB_TYPE: sqlite3
GITEA__database__PATH: /var/lib/gitea/data/gitea.db
GITEA__server__DOMAIN: ${GITEA_DOMAIN}
GITEA__server__ROOT_URL: https://${GITEA_DOMAIN}/
GITEA__server__DISABLE_SSH: "true"
GITEA__service__DISABLE_REGISTRATION: "true"
GITEA__security__INSTALL_LOCK: "true"
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:3000/api/healthz"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
nginx: nginx:
container_name: tapm-nginx
image: nginx:1.28-alpine image: nginx:1.28-alpine
restart: unless-stopped restart: unless-stopped
networks: networks:
-38
View File
@@ -1,38 +0,0 @@
name: tapm-gitea
services:
gitea:
container_name: tapm-gitea
image: docker.gitea.com/gitea:1.26.4-rootless
restart: unless-stopped
env_file:
- path: ../../.env
required: false
networks:
- edge
ports:
- "${GITEA_HTTP_PORT:-3000}:3000"
volumes:
- ../../config/gitea/data:/var/lib/gitea
- ../../config/gitea/config:/etc/gitea
environment:
GITEA__database__DB_TYPE: sqlite3
GITEA__database__PATH: /var/lib/gitea/data/gitea.db
GITEA__server__DOMAIN: ${GITEA_DOMAIN}
GITEA__server__ROOT_URL: https://${GITEA_DOMAIN}/
GITEA__server__DISABLE_SSH: "true"
GITEA__service__DISABLE_REGISTRATION: "true"
GITEA__security__INSTALL_LOCK: "true"
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:3000/api/healthz"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
networks:
edge:
external: true
name: tapm-edge
+28 -12
View File
@@ -4,24 +4,23 @@ The deployment is relocatable. Compose paths and management commands are
resolved relative to the repository checkout, so it can live anywhere on the resolved relative to the repository checkout, so it can live anywhere on the
VM. `/opt/idssys/TA-Deployment-Access` is only one possible example. VM. `/opt/idssys/TA-Deployment-Access` is only one possible example.
It consists of four containers: One Compose project manages:
- TAPM broker, with an embedded SQLite database - TAPM broker, with an embedded SQLite database
- Gitea, with its own embedded SQLite database and repository storage - Gitea, with its own embedded SQLite database and repository storage
- Nginx, terminating TLS for the broker and Gitea - Nginx, terminating TLS for the broker and Gitea
- Certbot, run on demand for certificate issuance and renewal - Certbot, as an on-demand utility for certificate issuance and renewal
The configured Nginx HTTP/HTTPS ports and Gitea HTTP port are published. They In production, only the configured Nginx HTTP and HTTPS ports are published.
default to 8680, 8643, and 3000. Inside Docker, Nginx continues to listen on They default to 8680 and 8643. Inside Docker, Nginx listens on ports 80 and 443,
ports 80 and 443 and Gitea listens on port 3000. Gitea SSH is disabled. the broker on 8080, and Gitea on 3000. Gitea SSH is disabled.
## 1. VM and network ## 1. VM and network
Install Docker Engine with Compose v2. Permit the selected HTTP and HTTPS ports Install Docker Engine with Compose v2. Permit the selected HTTP and HTTPS ports
and forward public TCP 80 and 443 from the datacenter edge to them. The and forward public TCP 80 and 443 from the datacenter edge to them. The
`GITEA_HTTP_PORT` binding is intended for direct local or management access and Create public DNS A/AAAA records for both application names before requesting
should be firewalled from untrusted networks. Create public DNS A/AAAA records the certificate.
for both application names before requesting the certificate.
Public port 80 must reach the container's port 80 for HTTP-01 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 renewal. For example, if `HTTP_PORT=8080`, the edge must forward public port 80
@@ -41,9 +40,8 @@ chmod 600 .env
Set `BROKER_DOMAIN`, `GITEA_DOMAIN`, and `LETSENCRYPT_EMAIL` first. `HTTP_PORT` 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 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 8643. The datacenter edge should therefore forward public ports 80 and 443 to
VM ports 8680 and 8643. `GITEA_HTTP_PORT` controls the host binding for Gitea's VM ports 8680 and 8643. Replace all example domains in the TAPM variables.
port 3000 and defaults to 3000. Replace all example domains in the TAPM Generate the cookie secret with:
variables. Generate the cookie secret with:
```sh ```sh
openssl rand -base64 48 openssl rand -base64 48
@@ -94,7 +92,7 @@ the repository or at an absolute host path.
Create the initial Gitea administrator: Create the initial Gitea administrator:
```sh ```sh
docker compose --env-file .env -f deploy/gitea/compose.yaml exec gitea \ docker compose exec gitea \
gitea admin user create \ gitea admin user create \
--admin --username taiadmin --email ADMIN-EMAIL \ --admin --username taiadmin --email ADMIN-EMAIL \
--password 'TEMPORARY-RANDOM-PASSWORD' --must-change-password --password 'TEMPORARY-RANDOM-PASSWORD' --must-change-password
@@ -121,6 +119,24 @@ curl --fail "https://GITEA_DOMAIN/api/healthz"
``` ```
The broker automatically applies SQLite schema migrations before starting. The broker automatically applies SQLite schema migrations before starting.
Gitea uses its own SQLite database at
`config/gitea/data/data/gitea.db`.
For local testing that bypasses Nginx, set `BROKER_DIRECT_PORT` and
`GITEA_DIRECT_PORT` in `.env`, then run:
```sh
./manage.sh start-direct
```
This adds host mappings to the broker's port 8080 and Gitea's port 3000. Do not
use the direct-port override on an Internet-facing production VM. Return to the
production port layout with:
```sh
./manage.sh start
docker compose -f compose.yaml -f compose.tls.yaml up -d --force-recreate broker gitea
```
## 5. Move repositories ## 5. Move repositories
+13 -12
View File
@@ -76,10 +76,6 @@ prepare() {
docker network create tapm-edge >/dev/null docker network create tapm-edge >/dev/null
} }
gitea_compose() {
docker compose --env-file .env -f deploy/gitea/compose.yaml "$@"
}
case "${1:-}" in case "${1:-}" in
prepare) prepare)
require_env require_env
@@ -88,8 +84,7 @@ prepare)
bootstrap) bootstrap)
require_env require_env
prepare prepare
gitea_compose up -d docker compose up -d gitea nginx
docker compose up -d nginx
if [[ "$SSL_MODE" == "letsencrypt" ]]; then if [[ "$SSL_MODE" == "letsencrypt" ]]; then
docker compose --profile tools run --rm certbot certonly \ docker compose --profile tools run --rm certbot certonly \
--webroot --webroot-path /var/www/certbot \ --webroot --webroot-path /var/www/certbot \
@@ -103,9 +98,17 @@ bootstrap)
start) start)
require_env require_env
prepare prepare
gitea_compose up -d
docker compose -f compose.yaml -f compose.tls.yaml up -d --build docker compose -f compose.yaml -f compose.tls.yaml up -d --build
;; ;;
start-direct)
require_env
prepare
docker compose \
-f compose.yaml \
-f compose.tls.yaml \
-f compose.direct.yaml \
up -d --build
;;
renew) renew)
require_env require_env
[[ "$SSL_MODE" == "letsencrypt" ]] || [[ "$SSL_MODE" == "letsencrypt" ]] ||
@@ -120,19 +123,17 @@ backup)
destination="config/backups/${stamp}" destination="config/backups/${stamp}"
mkdir -p "$destination" mkdir -p "$destination"
docker compose stop broker docker compose stop broker
gitea_compose stop gitea docker compose stop gitea
cp -a config/broker "$destination/" cp -a config/broker "$destination/"
cp -a config/gitea "$destination/" cp -a config/gitea "$destination/"
gitea_compose start gitea docker compose -f compose.yaml -f compose.tls.yaml start gitea broker
docker compose -f compose.yaml -f compose.tls.yaml start broker
printf 'Backup created at %s\n' "$destination" printf 'Backup created at %s\n' "$destination"
;; ;;
status) status)
docker compose -f compose.yaml -f compose.tls.yaml ps docker compose -f compose.yaml -f compose.tls.yaml ps
gitea_compose ps
;; ;;
*) *)
printf 'Usage: %s {prepare|bootstrap|start|renew|backup|status}\n' "$0" printf 'Usage: %s {prepare|bootstrap|start|start-direct|renew|backup|status}\n' "$0"
exit 2 exit 2
;; ;;
esac esac
+1 -2
View File
@@ -54,7 +54,7 @@ if ((post_pull == 0)); then
fi fi
printf 'Updating the local Gitea image and deployment stack...\n' printf 'Updating the local Gitea image and deployment stack...\n'
docker compose --env-file .env -f deploy/gitea/compose.yaml pull docker compose --env-file .env pull gitea nginx certbot
"${DEPLOY_ROOT}/manage.sh" start "${DEPLOY_ROOT}/manage.sh" start
container_id="$(docker compose -f compose.yaml -f compose.tls.yaml ps -q broker)" container_id="$(docker compose -f compose.yaml -f compose.tls.yaml ps -q broker)"
@@ -72,7 +72,6 @@ for ((attempt = 1; attempt <= 75; attempt++)); do
healthy) healthy)
printf ' healthy.\n' printf ' healthy.\n'
docker compose -f compose.yaml -f compose.tls.yaml ps docker compose -f compose.yaml -f compose.tls.yaml ps
docker compose --env-file .env -f deploy/gitea/compose.yaml ps
printf 'Local deployment updated successfully.\n' printf 'Local deployment updated successfully.\n'
exit 0 exit 0
;; ;;