Add LXC deploy script, Gitea Actions workflow and deploy docs
deploy / deploy (push) Canceled after 0s

This commit is contained in:
2026-09-06 19:28:35 +03:00
parent 73b90c81ee
commit 61919ab00d
6 changed files with 211 additions and 1 deletions
+30
View File
@@ -0,0 +1,30 @@
name: deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
# Requires a Gitea act runner with network access to the LXC host.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure SSH
run: |
install -m 600 /dev/null ~/.ssh/id_ed25519
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_ed25519
echo "${{ secrets.DEPLOY_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
- name: Deploy
env:
SSH_HOST: ${{ secrets.DEPLOY_HOST }} # e.g. deploy@10.0.0.42
SSH_PORT: ${{ secrets.DEPLOY_PORT }} # e.g. 2222
DEPLOY_DIR: ${{ secrets.DEPLOY_DIR }} # e.g. /opt/ai-rendezvous
DEPLOY_MODE: ${{ secrets.DEPLOY_MODE }} # docker | systemd
SERVICE_NAME: ${{ secrets.DEPLOY_SERVICE }} # systemd mode only
HEALTH_URL: ${{ secrets.DEPLOY_HEALTH_URL }} # e.g. http://127.0.0.1:3000/health
run: ./scripts/deploy.sh
+1
View File
@@ -4,3 +4,4 @@ data/
*.db *.db
*.db-* *.db-*
.env .env
deploy.env
+2 -1
View File
@@ -158,7 +158,8 @@ curl -H 'authorization: Bearer <token-a>' http://localhost:3000/api/rooms/<room>
``` ```
Full API reference: [docs/API.md](docs/API.md). MCP setup: Full API reference: [docs/API.md](docs/API.md). MCP setup:
[docs/MCP.md](docs/MCP.md). [docs/MCP.md](docs/MCP.md). Deploying to your own LXC via Gitea Actions or
webhooks: [docs/DEPLOY.md](docs/DEPLOY.md).
## Negotiation protocol in one paragraph ## Negotiation protocol in one paragraph
+18
View File
@@ -0,0 +1,18 @@
[Unit]
Description=AI Rendezvous server
After=network.target
[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/ai-rendezvous
ExecStart=/usr/bin/node packages/server/dist/src/index.js
Environment=PORT=3000
Environment=DB_PATH=/opt/ai-rendezvous/data/rendezvous.db
# Set to the public URL agents will see in invite links:
Environment=BASE_URL=http://localhost:3000
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
+89
View File
@@ -0,0 +1,89 @@
# Deploy to LXC
One script deploys everywhere: [`scripts/deploy.sh`](../scripts/deploy.sh).
It SSHes to the LXC host, does `git fetch + reset --hard origin/main`, rebuilds
and restarts the service, then hits the health check. It never keeps secrets
in the repo — configuration comes from env vars, a gitignored `deploy.env`, or
Gitea secrets.
## Target host (one-time setup on the LXC)
```bash
# as root on the LXC container:
apt install -y git # plus docker+compose, or node 22 for systemd mode
useradd -m -s /bin/bash deploy || true
# checkout (read-only deploy key tied to this repo, no push rights):
sudo -u deploy bash -c '
git clone git@git.omniagency.ru:2222/a.andreev/AI-Rendezvous.git /opt/ai-rendezvous'
chown -R deploy:deploy /opt/ai-rendezvous
```
Generate a read-only deploy key on the LXC (`sudo -u deploy ssh-keygen -t
ed25519`) and add the public key as a **read-only** deploy key in Gitea
(repo Settings → Deploy keys, *without* write access).
Choose how the service runs:
- **docker mode (default):** `docker compose up -d` is used on every deploy.
Prepare `.env` with `BASE_URL=https://rendezvous.example` next to
`docker-compose.yml` on the LXC.
- **systemd mode:** install
[`ai-rendezvous.service`](../contrib/ai-rendezvous.service) and set
`DEPLOY_MODE=systemd`.
## Option A — Gitea Actions (recommended)
Add repository secrets (Settings → Actions → Secrets):
| Secret | Example | Notes |
|---|---|---|
| `DEPLOY_HOST` | `deploy@10.0.0.42` | user@lxc-container |
| `DEPLOY_PORT` | `22` | |
| `DEPLOY_DIR` | `/opt/ai-rendezvous` | |
| `DEPLOY_MODE` | `docker` | or `systemd` |
| `DEPLOY_SERVICE` | `ai-rendezvous` | systemd mode only |
| `DEPLOY_HEALTH_URL` | `http://127.0.0.1:3000/health` | checked via SSH on the LXC |
| `DEPLOY_SSH_KEY` | *(private key)* | key of a user allowed to deploy (not the read-only one) |
| `DEPLOY_KNOWN_HOSTS` | output of `ssh-keyscan -p 22 10.0.0.42` | |
`.gitea/workflows/deploy.yml` runs `scripts/deploy.sh` on every push to
`main`. Needs one act runner registered in Gitea (can run anywhere with SSH
access to the LXC — including the LXC itself).
## Option B — Gitea webhook
If you don't want an act runner: add a webhook (Settings → Webhooks) pointing
to a minimal receiver on the LXC (e.g. `webhook`/` webhookd`/a 20-line HTTP
server) that verifies the shared secret and executes:
```bash
sudo -u deploy env SSH_HOST=deploy@localhost DEPLOY_MODE=docker \
/opt/ai-rendezvous/scripts/deploy.sh
```
Gitea → webhook → receiver → `deploy.sh`. Same script, no CI needed.
## Option C — manual / from a dev machine (or the agent's shell)
```bash
./scripts/deploy.sh # reads deploy.env (gitignored) if present
```
`deploy.env` example:
```bash
SSH_HOST=deploy@lxc42.internal
SSH_PORT=22
DEPLOY_DIR=/opt/ai-rendezvous
DEPLOY_MODE=docker
HEALTH_URL=http://127.0.0.1:3000/health
```
## Deploy flow for the agent
1. Make changes, `npm test` locally.
2. Commit and push to `main` on Gitea.
3. Gitea Actions (or webhook) runs `scripts/deploy.sh`.
4. The health check must pass; the action fails loudly otherwise.
5. Human verifies on the deployed instance.
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Deploy AI Rendezvous to the LXC host over SSH.
#
# Works in three ways:
# 1. locally: ./scripts/deploy.sh
# 2. from Gitea Actions: .gitea/workflows/deploy.yml calls this script
# 3. from a webhook: any tiny receiver on the LXC can exec this script
#
# Configuration via environment (or a gitignored deploy.env next to this file):
# SSH_HOST user@lxc-host (required)
# SSH_PORT 22
# DEPLOY_DIR /opt/ai-rendezvous checkout on the LXC
# BRANCH main
# DEPLOY_MODE docker | systemd how to run the service
# SERVICE_NAME ai-rendezvous systemd unit name (systemd mode)
# HEALTH_URL e.g. http://127.0.0.1:3000/health checked after deploy
set -euo pipefail
cd "$(dirname "$0")/.."
# shellcheck disable=SC1091
[ -f deploy.env ] && . ./deploy.env
: "${SSH_HOST:?Set SSH_HOST (user@lxc-host) via env, deploy.env or CI secrets}"
SSH_PORT="${SSH_PORT:-22}"
DEPLOY_DIR="${DEPLOY_DIR:-/opt/ai-rendezvous}"
BRANCH="${BRANCH:-main}"
DEPLOY_MODE="${DEPLOY_MODE:-docker}"
SERVICE_NAME="${SERVICE_NAME:-ai-rendezvous}"
HEALTH_URL="${HEALTH_URL:-}"
SSH_CMD=(ssh -p "$SSH_PORT" -o StrictHostKeyChecking=accept-new "$SSH_HOST")
echo "==> Deploying $BRANCH to $SSH_HOST:$DEPLOY_DIR (mode: $DEPLOY_MODE)"
"${SSH_CMD[@]}" BRANCH="$BRANCH" DEPLOY_DIR="$DEPLOY_DIR" DEPLOY_MODE="$DEPLOY_MODE" \
SERVICE_NAME="$SERVICE_NAME" bash -s <<'REMOTE'
set -euo pipefail
cd "$DEPLOY_DIR"
echo "--> fetching $BRANCH"
umask 022
git fetch --prune origin
git reset --hard "origin/$BRANCH"
if [ "$DEPLOY_MODE" = "docker" ]; then
echo "--> rebuilding containers"
docker compose up -d --build --remove-orphans
elif [ "$DEPLOY_MODE" = "systemd" ]; then
echo "--> building"
npm ci --no-audit --no-fund
npm run build
echo "--> restarting $SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
else
echo "unknown DEPLOY_MODE: $DEPLOY_MODE" >&2
exit 1
fi
REMOTE
if [ -n "$HEALTH_URL" ]; then
echo "==> Health check $HEALTH_URL"
if "${SSH_CMD[@]}" curl -sf --max-time 5 --retry 10 --retry-delay 3 --retry-connrefused "$HEALTH_URL" >/dev/null; then
echo "==> healthy"
else
echo "!! health check FAILED after deploy" >&2
exit 1
fi
fi
echo "==> deploy OK"