Files
orion/docs/deployment/gitea.md
Samir Boulahtit 11f1909f68
Some checks failed
CI / ruff (push) Successful in 8s
CI / pytest (push) Successful in 36m19s
CI / architecture (push) Successful in 11s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 9s
CI / docs (push) Failing after 59s
CI / deploy (push) Failing after 3s
feat(cd): add continuous deployment on push to master
Deploy job SSHes to production after ruff/pytest/architecture pass,
running scripts/deploy.sh (stash, pull, docker rebuild, migrate, health check).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:42:13 +01:00

309 lines
8.5 KiB
Markdown

# Gitea CI/CD Deployment Guide
This document describes how to **self-host Gitea** on an external server and migrate CI/CD from GitLab to **Gitea Actions** (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 GitLab
- Low resource usage compared to GitLab
---
## 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 **GitLab** as the source.
3. Enter your GitLab URL and a Personal Access Token.
4. Gitea will import the repository, issues, labels, milestones, and merge requests.
---
## 6. CI/CD — GitLab vs Gitea Actions
The workflow file lives in `.gitea/workflows/ci.yml` (already created in this repository).
| GitLab CI (`.gitlab-ci.yml`) | Gitea Actions (`.gitea/workflows/ci.yml`) |
|------------------------------|-------------------------------------------|
| `stages:` + `stage:` per job | Jobs run in parallel; use `needs:` for ordering |
| `services:` (top-level on job) | `services:` nested under each job with `options:` |
| `allow_failure: true` | `continue-on-error: true` |
| `rules: - if:` | `on:` triggers + `if:` conditionals per job |
| `artifacts: paths:` | `actions/upload-artifact@v4` |
| `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` | Production server IP (e.g. `127.0.0.1`) | 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 |
---
## 8. Pipeline Overview
The CI pipeline (`.gitea/workflows/ci.yml`) runs:
```
push/PR to master
├── ruff (lint)
├── pytest (tests + PostgreSQL service)
├── architecture (architecture validation)
├── dependency-scanning (pip-audit, non-blocking)
├── audit (custom audit, non-blocking)
├── docs (mkdocs build, master-only, after lint+test pass)
└── deploy (SSH deploy, master-only, after lint+test+arch pass)
```
All jobs run in parallel except `docs` and `deploy`, which wait for `ruff`, `pytest`, and `architecture` 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, architecture]
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'
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
```
---
## 12. Removing GitLab (After Migration)
Once you have verified everything works on Gitea:
1. Update your local git remote:
```bash
git remote set-url origin ssh://git@git.yourdomain.com:2222/your-username/letzshop-product-import.git
```
2. The `.gitlab-ci.yml` file can be removed from the repository.
3. Archive or delete the GitLab project.