Files
orion/docs/deployment/gitea.md
Samir Boulahtit b382090771
Some checks failed
CI / ruff (push) Successful in 12s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled
refactor: remove GitLab CI config and docs after full Gitea migration
- Delete .gitlab-ci.yml (replaced by .gitea/workflows/ci.yml)
- Delete docs/deployment/gitlab.md (superseded by gitea.md)
- Update audit rules to reference .gitea/workflows/*.yml
- Update validate_audit.py to check Gitea CI paths
- Clean up GitLab references in gitea.md, mkdocs.yml, .dockerignore
- Mark IPv6 AAAA records as completed in hetzner docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 19:28:35 +01:00

295 lines
8.3 KiB
Markdown

# Gitea CI/CD Deployment Guide
This document describes how to **self-host Gitea** on an external server with **Gitea Actions** CI/CD (GitHub Actions-compatible).
---
## Why Gitea?
- Lightweight, self-hosted Git forge (single binary or Docker image)
- Built-in CI/CD via **Gitea Actions** (GitHub Actions-compatible YAML)
- Built-in migration tool imports repos, issues, and PRs from other forges
- Low resource usage
---
## 1. Server Prerequisites
```bash
# Ubuntu/Debian
sudo apt update && sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER # log out/in after this
```
---
## 2. Gitea Server Setup (Docker Compose)
Create a directory on your server:
```bash
mkdir -p ~/gitea && cd ~/gitea
```
Create `docker-compose.yml`:
```yaml
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: always
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=<CHANGE_ME>
- GITEA__server__ROOT_URL=https://git.yourdomain.com/
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
- GITEA__server__DOMAIN=git.yourdomain.com
- GITEA__actions__ENABLED=true
volumes:
- gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000" # Web UI
- "2222:22" # SSH (Git over SSH)
depends_on:
gitea-db:
condition: service_healthy
gitea-db:
image: postgres:15
container_name: gitea-db
restart: always
environment:
POSTGRES_DB: gitea
POSTGRES_USER: gitea
POSTGRES_PASSWORD: <CHANGE_ME>
volumes:
- gitea-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea"]
interval: 10s
timeout: 5s
retries: 5
# Gitea Actions runner — executes CI workflows
gitea-runner:
image: gitea/act_runner:latest
container_name: gitea-runner
restart: always
environment:
GITEA_INSTANCE_URL: http://gitea:3000
GITEA_RUNNER_REGISTRATION_TOKEN: <RUNNER_TOKEN>
GITEA_RUNNER_NAME: default-runner
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- gitea-runner-data:/data
depends_on:
- gitea
volumes:
gitea-data:
gitea-db-data:
gitea-runner-data:
```
!!! warning "Replace placeholders"
Replace `<CHANGE_ME>` with a strong database password and `<RUNNER_TOKEN>` with the token from step 4.
Start Gitea and the database first:
```bash
docker compose up -d gitea gitea-db
```
Visit `http://your-server-ip:3000` and complete the initial setup wizard.
---
## 3. Reverse Proxy with HTTPS (Nginx + Let's Encrypt)
```bash
sudo apt install -y nginx certbot python3-certbot-nginx
```
Create `/etc/nginx/sites-available/gitea`:
```nginx
server {
server_name git.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 100M;
}
}
```
Enable and get a certificate:
```bash
sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
sudo certbot --nginx -d git.yourdomain.com
sudo systemctl reload nginx
```
---
## 4. Enable Actions & Register the Runner
1. Go to **Site Administration > Runners** in the Gitea web UI.
2. Click **Create new Runner** and copy the registration token.
3. Paste the token into `docker-compose.yml` as `GITEA_RUNNER_REGISTRATION_TOKEN`.
4. Start the runner:
```bash
docker compose up -d gitea-runner
```
Verify the runner appears as **Online** in the admin panel.
---
## 5. Migrate Your Repository
### Option A: Git push (code only)
```bash
# On your local machine
cd /path/to/letzshop-product-import
git remote add gitea ssh://git@git.yourdomain.com:2222/your-username/letzshop-product-import.git
git push gitea --all
git push gitea --tags
```
### Option B: Gitea built-in migration (code + issues + PRs)
1. In Gitea, click **+** > **New Migration**.
2. Select the source forge (GitHub, GitLab, etc.).
3. Enter the source URL and a Personal Access Token.
4. Gitea will import the repository, issues, labels, milestones, and pull/merge requests.
---
## 6. CI/CD — Gitea Actions
The workflow file lives in `.gitea/workflows/ci.yml` (already created in this repository). Gitea Actions uses GitHub Actions-compatible YAML syntax.
| `artifacts: paths:` | `actions/upload-artifact@v4` (not supported on Gitea GHES) |
| `cache: paths:` | `actions/cache@v4` |
| `coverage: '/regex/'` | Use coverage action or parse in step |
| CI/CD Variables (UI) | Repository **Settings > Secrets** |
---
## 7. CI/CD Secrets
Configure these in your Gitea repository under **Settings > Actions > Secrets**:
| Secret | Description | Used by |
|--------|-------------|---------|
| `DEPLOY_SSH_KEY` | Ed25519 private key for deployment | Deploy job |
| `DEPLOY_HOST` | Docker bridge gateway IP: `172.17.0.1` (see note below) | Deploy job |
| `DEPLOY_USER` | SSH user on production server (e.g. `samir`) | Deploy job |
| `DEPLOY_PATH` | App directory on server (e.g. `/home/samir/apps/orion`) | Deploy job |
!!! important "DEPLOY_HOST must be `172.17.0.1`, not `127.0.0.1`"
The Gitea Actions runner executes CI jobs inside Docker containers. From inside the container, `127.0.0.1` refers to the container itself, not the host machine. Use `172.17.0.1` (the Docker bridge gateway) so the SSH action can reach the host's SSH daemon. When Gitea and Orion are split onto separate servers, update this to the Orion server's real IP.
---
## 8. Pipeline Overview
The CI pipeline (`.gitea/workflows/ci.yml`) runs:
```
push/PR to master
├── ruff (lint)
├── pytest (tests + PostgreSQL service)
├── validate (all 4 validators: architecture, security, performance, audit)
├── dependency-scanning (pip-audit, non-blocking)
├── docs (mkdocs build, master-only, after lint+test+validate pass)
└── deploy (SSH deploy, master-only, after lint+test+validate pass)
```
All jobs run in parallel except `docs` and `deploy`, which wait for `ruff`, `pytest`, and `validate` to pass. The `deploy` job only runs on push (not PRs).
---
## 9. Deploy Job (Continuous Deployment)
The CI pipeline includes an automated deploy job that runs on every successful push to master. It SSHes to the production server and runs a version-controlled deploy script:
```yaml
deploy:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
needs: [ruff, pytest, validate]
steps:
- name: Deploy to production
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: 22
command_timeout: 10m
script: cd ${{ secrets.DEPLOY_PATH }} && bash scripts/deploy.sh
```
The `scripts/deploy.sh` script handles the full deploy lifecycle:
1. Stash local changes (preserves `.env` and other server-side edits)
2. Pull latest code (`--ff-only`)
3. Pop stash to restore local changes
4. Rebuild and restart Docker containers (`docker compose --profile full up -d --build`)
5. Run database migrations (`alembic upgrade heads`)
6. Health check `http://localhost:8001/health` with retries
See [Hetzner Server Setup — Step 16](hetzner-server-setup.md#step-16-continuous-deployment) for the full setup guide including SSH key generation and Gitea secrets configuration.
---
## 10. Firewall Configuration
```bash
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
# Allow CI containers (Docker bridge) to SSH to the host for deployment
sudo ufw allow from 172.17.0.0/16 to any port 22
sudo ufw enable
```
---
## 11. Maintenance
```bash
# View Gitea logs
docker compose -f ~/gitea/docker-compose.yml logs -f gitea
# View runner logs
docker compose -f ~/gitea/docker-compose.yml logs -f gitea-runner
# Update Gitea
cd ~/gitea
docker compose pull
docker compose up -d
# Backup Gitea data
docker run --rm -v gitea-data:/data -v $(pwd):/backup alpine \
tar czf /backup/gitea-backup-$(date +%Y%m%d).tar.gz /data
```
---