Add LXC deploy script, Gitea Actions workflow and deploy docs
deploy / deploy (push) Canceled after 0s
deploy / deploy (push) Canceled after 0s
This commit is contained in:
@@ -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
|
||||
@@ -4,3 +4,4 @@ data/
|
||||
*.db
|
||||
*.db-*
|
||||
.env
|
||||
deploy.env
|
||||
|
||||
@@ -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:
|
||||
[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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
Executable
+71
@@ -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"
|
||||
Reference in New Issue
Block a user