chore(repo): initialize team collaboration repository
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run

This commit is contained in:
2026-07-27 20:40:12 +08:00
commit c91a64fddb
109 changed files with 21121 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
# Gitea deployment
The team Git service runs as Gitea 1.27.0 on the existing CVM:
- public URL: `https://git.imagebrewing.com`;
- container HTTP bind: `127.0.0.1:13000`;
- persistent data: `/data/gitea/data`;
- database: Gitea-managed SQLite;
- Git transport: HTTPS only; no extra public SSH port;
- anonymous users may browse public repositories;
- account registration requires administrator approval before sign-in.
- daily backup target: `/chucun/wangzhan-production/backups/gitea/`.
The service is intentionally separate from the FlashOps runtime and database.
Back up `/data/gitea/data` before an image upgrade. Pin the image version and
review the Gitea release notes before changing it.
The current server does not have the Docker Compose plugin. The checked-in
`docker-compose.yml` is the declarative service record for future rebuilds;
the running container was created with the equivalent pinned `docker run`
settings. Routine checks and restarts therefore use Docker directly:
```bash
sudo docker ps --filter name=^gitea$
sudo docker restart gitea
sudo docker logs --tail 100 gitea
curl -fsS http://127.0.0.1:13000/api/healthz
```
Install Compose or recreate the container from the checked-in definition only
during a planned maintenance window, after a verified backup.
Nginx terminates HTTPS and proxies to the loopback-only container port. Run
`nginx -t` before every reload. Credentials and API tokens are never stored in
this directory or committed to Git.
`gitea-backup.timer` runs daily at 03:20 Asia/Shanghai with a randomized delay.
It uses Gitea's own dump command, writes the ZIP and SHA-256 sidecar to the
mounted COS bucket, and removes the temporary local dump after a successful copy.
The live repository and SQLite database remain on the local filesystem because
COSFS is a backup destination, not a POSIX database filesystem.
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
backup_dir=/chucun/wangzhan-production/backups/gitea
container_dump=/data/gitea-backup.zip
host_dump=/data/gitea/data/gitea-backup.zip
stamp=$(date -u +%Y%m%dT%H%M%SZ)
target="$backup_dir/gitea-$stamp.zip"
install -d -o ubuntu -g ubuntu -m 0770 "$backup_dir"
if [ -e "$host_dump" ]; then
unlink "$host_dump"
fi
docker exec -u git gitea sh -c \
'mkdir -p /tmp/gitea-dump && find /tmp/gitea-dump -mindepth 1 -delete'
docker exec -u git gitea gitea dump \
--config /data/gitea/conf/app.ini \
--file "$container_dump" \
--tempdir /tmp/gitea-dump
cp "$host_dump" "$target"
sha256sum "$target" > "$target.sha256"
unlink "$host_dump"
printf 'Gitea backup created: %s\n' "$target"
+28
View File
@@ -0,0 +1,28 @@
services:
gitea:
image: gitea/gitea:1.27.0
container_name: gitea
restart: unless-stopped
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: sqlite3
GITEA__database__PATH: /data/gitea/gitea.db
GITEA__server__DOMAIN: git.imagebrewing.com
GITEA__server__ROOT_URL: https://git.imagebrewing.com/
GITEA__server__HTTP_PORT: "3000"
GITEA__server__DISABLE_SSH: "true"
GITEA__server__OFFLINE_MODE: "true"
GITEA__service__DISABLE_REGISTRATION: "false"
GITEA__service__REGISTER_MANUAL_CONFIRM: "true"
GITEA__service__REQUIRE_SIGNIN_VIEW: "false"
GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION: "false"
GITEA__repository__DEFAULT_PRIVATE: public
GITEA__security__INSTALL_LOCK: "true"
GITEA__cron__ENABLED: "true"
GITEA__log__MODE: console
GITEA__log__LEVEL: Info
ports:
- "127.0.0.1:13000:3000"
volumes:
- /data/gitea/data:/data
@@ -0,0 +1,11 @@
[Unit]
Description=Back up Gitea to mounted COS bucket
Requires=docker.service
After=docker.service network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/flashops-gitea-backup
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Daily Gitea backup timer
[Timer]
OnCalendar=*-*-* 03:20:00 Asia/Shanghai
RandomizedDelaySec=10m
Persistent=true
Unit=flashops-gitea-backup.service
[Install]
WantedBy=timers.target
+25
View File
@@ -0,0 +1,25 @@
server {
listen 80;
server_name git.imagebrewing.com;
access_log /www/wwwlogs/git.imagebrewing.com.log;
error_log /www/wwwlogs/git.imagebrewing.com.error.log;
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
default_type text/plain;
}
location / {
proxy_pass http://127.0.0.1:13000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
+47
View File
@@ -0,0 +1,47 @@
server {
listen 80;
server_name git.imagebrewing.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
default_type text/plain;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
http2 on;
server_name git.imagebrewing.com;
ssl_certificate /etc/letsencrypt/live/git.imagebrewing.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/git.imagebrewing.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_timeout 1d;
ssl_session_cache shared:GiteaSSL:10m;
ssl_session_tickets off;
access_log /www/wwwlogs/git.imagebrewing.com.log;
error_log /www/wwwlogs/git.imagebrewing.com.error.log;
client_max_body_size 100m;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header X-Frame-Options SAMEORIGIN always;
location / {
proxy_pass http://127.0.0.1:13000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}