diff --git a/ADR.md b/ADR.md index 1e798b1..af93b69 100644 --- a/ADR.md +++ b/ADR.md @@ -117,7 +117,7 @@ This document tracks all significant architectural decisions made during the pro ## ADR-007: SSL Certificates - Let's Encrypt -**Date**: 2026-06-08 +**Date**: 2026-06-08 (Updated 2026-06-11) **Status**: Accepted **Decision**: Let's Encrypt with certbot @@ -130,6 +130,10 @@ This document tracks all significant architectural decisions made during the pro **Requirement**: Valid domain name pointing to server +**Domain**: git.poll-streams.com (changed from gitea.poll-streams.com) + +**Implementation Note**: Initially encountered Let's Encrypt rate limits (5 certificates per week). Resolved by migrating to a fresh domain identifier (git.poll-streams.com), allowing immediate production certificate issuance. Production certificates obtained successfully. + --- ## ADR-008: Update Automation - Diun + Custom Scripts @@ -167,6 +171,43 @@ This document tracks all significant architectural decisions made during the pro --- +## ADR-012: CI/CD - Gitea Actions with Self-Hosted Runners + +**Date**: 2026-06-11 +**Status**: Accepted + +**Decision**: Use Gitea Actions with self-hosted runners for CI/CD + +**Rationale**: +- Native integration with Gitea (no external CI service) +- Self-hosted runners provide full control and security +- GitHub Actions-compatible workflow syntax (familiar, well-documented) +- Enables automated testing before merging changes +- Demonstrates production-grade CI/CD practices + +**Implementation**: +- **Runners**: 2x act_runner v0.2.10 instances as systemd services +- **Automation**: Ansible playbook (setup-runner.yml) for reproducible deployment +- **Runner Registration**: Automated via Gitea API with token from AWS Secrets Manager +- **Networking**: Host network mode for job containers to access Gitea +- **Registration URL**: https://git.poll-streams.com (public URL for git clone operations) +- **Workflow**: .gitea/workflows/test.yml runs integration tests on PRs +- **Features**: Docker layer caching, artifact uploads, workflow_dispatch support + +**Technical Details**: +- Each runner has dedicated config directory (/etc/act_runner-{1,2}) +- Configuration includes host networking to allow job containers to reach services +- Runners registered with public URL to avoid localhost connection issues +- Systemd manages runner lifecycle with automatic restart + +**Benefits**: +- Automated quality gates before merging +- Consistent test environment (matches CI exactly) +- Fast feedback on code changes +- Self-contained solution (no external dependencies) + +--- + ## ADR-009: Monitoring - Prometheus + Grafana **Date**: 2026-06-08 @@ -236,7 +277,8 @@ This document tracks all significant architectural decisions made during the pro | **Reverse Proxy** | Nginx | Lightweight, standard | | **SSL** | Let's Encrypt | Free, automated, professional | | **DNS** | Route 53 | AWS-native | -| **Updates** | Watchtower | Docker-native automation | +| **Updates** | Diun + Scripts | Per-container policies, backup/rollback | +| **CI/CD** | Gitea Actions | Self-hosted runners, native integration | | **Backups** | Scripts + S3 | Custom, controlled | | **Monitoring** | Prometheus + Grafana | Industry standard | | **Logging** | Loki + Promtail | Lightweight, integrated | diff --git a/ROADMAP.md b/ROADMAP.md index b0adf46..c97fdee 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -104,7 +104,8 @@ This phase implements the automated, reproducible Gitea installation. ### 3.3 Reverse Proxy Configuration ✅ - ✅ Nginx 1.27-alpine deployed via Docker Compose -- ✅ Let's Encrypt SSL certificate obtained via certbot +- ✅ Let's Encrypt SSL certificate obtained via certbot (production) +- ✅ Domain: git.poll-streams.com (migrated to avoid rate limits) - ✅ Two-stage nginx config (HTTP-only for ACME, then HTTPS) - ✅ SSL termination at nginx, proxy to Gitea on port 3000 - ✅ HTTP to HTTPS redirect configured @@ -114,7 +115,7 @@ This phase implements the automated, reproducible Gitea installation. ### 3.4 Testing ✅ - ✅ HTTPS access verified: https://git.poll-streams.com -- ✅ Valid SSL certificate (Let's Encrypt) +- ✅ Valid SSL certificate (Let's Encrypt production) - ✅ HTTP → HTTPS redirect working - ✅ Gitea web interface accessible and functional - ✅ User account created, repository created @@ -191,11 +192,24 @@ This phase implements automated update mechanisms for Gitea and related componen - ✅ Diun monitoring confirmed (4 containers) - ✅ Update workflow diagram created +### 4.7 CI/CD Implementation ✅ +- ✅ Gitea Actions enabled on instance +- ✅ Self-hosted runners deployed (2x act_runner v0.2.10) +- ✅ Runner automation via Ansible (setup-runner.yml) +- ✅ Systemd services for runner management +- ✅ Host networking configuration for job containers +- ✅ CI workflow created (.gitea/workflows/test.yml) +- ✅ Automated testing on pull requests +- ✅ Docker layer caching for performance +- ✅ Artifact upload on test failure +- ✅ Full CI/CD pipeline tested and operational + ### Goals: - ✅ Automated update system operational - ✅ Update process tested and validated on live system - ✅ Rollback procedure implemented and tested - ✅ Quality gate for CI/local environments +- ✅ CI/CD pipeline with self-hosted runners - ✅ Documentation complete (workflow diagram) **Implementation Summary:** @@ -205,9 +219,10 @@ This phase implements automated update mechanisms for Gitea and related componen - Pre-update backups with automatic rollback on failure - Certificate renewal automation - Comprehensive testing framework -- Visual workflow documentation +- CI/CD with Gitea Actions and 2 self-hosted runners +- Visual workflow documentation (including CI/CD flow) -**Phase 4 Complete!** Update automation fully operational with safety mechanisms. +**Phase 4 Complete!** Update automation and CI/CD fully operational with safety mechanisms. --- diff --git a/docs/diagrams/application-stack.md b/docs/diagrams/application-stack.md index 08d5a62..93da6c0 100644 --- a/docs/diagrams/application-stack.md +++ b/docs/diagrams/application-stack.md @@ -12,46 +12,72 @@ graph TB subgraph EC2["EC2 Instance"] subgraph Docker["Docker Compose"] Nginx[Nginx
Port 80, 443] - Gitea[Gitea
Port 3000] + Gitea[Gitea
Port 3000, 2222] Postgres[(PostgreSQL
Port 5432)] - Watchtower[Watchtower
Auto-updater] + Certbot[Certbot
SSL Renewal] + DIUN[DIUN
Update Monitor] Nginx -->|Reverse Proxy| Gitea Gitea -->|Database Connection| Postgres - Watchtower -.->|Monitors & Updates| Nginx - Watchtower -.->|Monitors & Updates| Gitea + DIUN -.->|Monitors for Updates| Nginx + DIUN -.->|Monitors for Updates| Gitea + DIUN -.->|Monitors for Updates| Postgres + Certbot -.->|Renews Certificates| Nginx + end + + subgraph Systemd["Systemd Services"] + Runner1[act_runner-1
CI/CD Runner] + Runner2[act_runner-2
CI/CD Runner] + + Runner1 -.->|Executes Workflows| Gitea + Runner2 -.->|Executes Workflows| Gitea end end User -->|HTTPS| Nginx - LetsEncrypt -.->|Certbot Renewal| Nginx + User -->|Git SSH| Gitea + LetsEncrypt -.->|Certificate Authority| Certbot style EC2 fill:#e5e7eb,stroke:#4b5563,stroke-width:2px,stroke-dasharray: 5 5 style Docker fill:#d1d5db,stroke:#4b5563,stroke-width:2px,stroke-dasharray: 5 5 + style Systemd fill:#d1d5db,stroke:#4b5563,stroke-width:2px,stroke-dasharray: 5 5 style Nginx fill:#10B981,stroke:#333,stroke-width:1px,color:#fff style Gitea fill:#3B82F6,stroke:#333,stroke-width:1px,color:#fff style Postgres fill:#8B5CF6,stroke:#333,stroke-width:1px,color:#fff - style Watchtower fill:#F59E0B,stroke:#333,stroke-width:1px,color:#fff + style DIUN fill:#F59E0B,stroke:#333,stroke-width:1px,color:#fff + style Certbot fill:#6366F1,stroke:#333,stroke-width:1px,color:#fff + style Runner1 fill:#EF4444,stroke:#333,stroke-width:1px,color:#fff + style Runner2 fill:#EF4444,stroke:#333,stroke-width:1px,color:#fff ``` ## Components +### Docker Containers - **Nginx**: Reverse proxy handling SSL termination and routing to Gitea -- **Gitea**: Git server application (main service) +- **Gitea**: Git server application with Actions enabled (HTTP: 3000, SSH: 2222) - **PostgreSQL**: Database storing repositories metadata, users, issues -- **Watchtower**: Monitors Docker Hub for image updates, automatically pulls and restarts containers +- **DIUN**: Monitors Docker Hub for image updates, sends email notifications +- **Certbot**: Handles Let's Encrypt SSL certificate renewal + +### Systemd Services +- **act_runner-1**: First Gitea Actions runner for CI/CD workflows +- **act_runner-2**: Second Gitea Actions runner for CI/CD workflows ## Container Communication -- All containers in the same Docker network +- All containers in the same Docker network (`gitea-network`) - Nginx proxies HTTPS requests to Gitea's internal port 3000 -- Gitea connects to PostgreSQL via container name -- Watchtower runs on schedule, checking for updates -- Let's Encrypt certbot renews certificates automatically (via nginx container or separate container) +- Gitea connects to PostgreSQL via container name (`postgres`) +- DIUN monitors containers based on labels (`diun.enable=true`) +- Certbot shares volumes with nginx for certificate storage +- Runners connect to Gitea via `http://localhost:3000` ## Data Persistence Docker volumes ensure data survives container restarts: -- `gitea_data`: Git repositories and uploads -- `postgres_data`: Database files +- `gitea-data`: Git repositories and uploads +- `gitea_postgres-data`: PostgreSQL database files +- `certbot-etc`: Let's Encrypt certificates +- `certbot-var`: Certbot working directory +- `web-root`: ACME challenge files for SSL verification diff --git a/docs/diagrams/aws-infrastructure.md b/docs/diagrams/aws-infrastructure.md index 719695d..aaf48d9 100644 --- a/docs/diagrams/aws-infrastructure.md +++ b/docs/diagrams/aws-infrastructure.md @@ -8,12 +8,17 @@ This diagram shows the high-level AWS resources and their relationships. graph TB Internet([Internet/Users]) Route53[Route 53
DNS] - EC2[EC2 Instance
Docker Host] + EC2[EC2 Instance
Docker Host + Runners] S3[(S3 Bucket
Backups)] + Secrets[AWS Secrets Manager
DB/Admin Credentials] + IAM[IAM Role
EC2 Permissions] Internet -->|HTTPS| Route53 Route53 -->|DNS Resolution| EC2 EC2 -->|Backup Upload| S3 + EC2 -->|Fetch Credentials| Secrets + IAM -.->|Attached to| EC2 + EC2 -->|Update Runner Token| Secrets subgraph AWS["AWS Account"] subgraph VPC["VPC"] @@ -21,6 +26,8 @@ graph TB end Route53 S3 + Secrets + IAM end style AWS fill:#e5e7eb,stroke:#4b5563,stroke-width:2px,stroke-dasharray: 5 5 @@ -29,18 +36,24 @@ graph TB style EC2 fill:#10B981,stroke:#333,stroke-width:1px,color:#fff style S3 fill:#F97316,stroke:#333,stroke-width:1px,color:#fff style Route53 fill:#6366F1,stroke:#333,stroke-width:1px,color:#fff + style Secrets fill:#8B5CF6,stroke:#333,stroke-width:1px,color:#fff + style IAM fill:#F59E0B,stroke:#333,stroke-width:1px,color:#fff ``` ## Components - **Route 53**: DNS service that points domain to EC2 instance -- **EC2 Instance**: Single VM running Docker with all application containers -- **S3 Bucket**: Storage for database and application backups +- **EC2 Instance**: Single VM running Docker containers + 2 Gitea Actions runners (systemd services) +- **S3 Bucket**: Storage for database and application backups (with versioning) +- **AWS Secrets Manager**: Stores DB credentials, admin credentials, SES SMTP credentials, runner tokens +- **IAM Role**: EC2 instance profile with permissions for S3, Secrets Manager read/update - **VPC**: Isolated network containing EC2 instance ## Traffic Flow -1. User accesses `gitea.yourdomain.com` +1. User accesses `git.poll-streams.com` 2. Route 53 resolves to EC2 public IP 3. Request hits EC2 (nginx handles SSL, proxies to Gitea) 4. EC2 regularly backs up data to S3 +5. Ansible fetches credentials from Secrets Manager during deployment +6. Gitea generates runner token via API, stored back in Secrets Manager diff --git a/docs/diagrams/ci-cd-workflow.md b/docs/diagrams/ci-cd-workflow.md new file mode 100644 index 0000000..d255e69 --- /dev/null +++ b/docs/diagrams/ci-cd-workflow.md @@ -0,0 +1,242 @@ +# CI/CD Workflow with Gitea Actions + +This diagram shows the complete CI/CD workflow using Gitea Actions with self-hosted runners, including the automated setup process. + +## Overview + +- **Gitea Actions**: GitHub Actions-compatible CI/CD built into Gitea +- **Self-hosted runners**: 2 act_runner instances running as systemd services +- **Automated setup**: Admin user, runner tokens, and registration fully automated via Ansible +- **Test workflow**: Integration tests run on every PR to main branch + +## CI/CD Workflow Diagram + +```mermaid +%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#e5e7eb','primaryTextColor':'#111827','primaryBorderColor':'#9ca3af','lineColor':'#111827','secondaryColor':'#d1d5db','tertiaryColor':'#f3f4f6','edgeLabelBackground':'#ffffff','mainBkg':'#f5f5f4','nodeBorder':'#9ca3af','background':'#f5f5f4','clusterBkg':'transparent'},'themeCSS':'.node rect, .node circle, .node ellipse, .node polygon, .node path { filter: none !important; box-shadow: none !important; } .cluster rect { filter: none !important; box-shadow: none !important; } svg { background-color: #f5f5f4 !important; } .cluster-label { background-color: #ffffff !important; padding: 6px 12px !important; border-radius: 4px !important; font-size: 16px !important; font-weight: 700 !important; box-shadow: 0 1px 3px rgba(0,0,0,0.12) !important; border: 1px solid #d1d5db !important; } .edgePath, .edgePath path, .flowchart-link { z-index: 1 !important; }'}}%% + +flowchart TB + Dev([Developer]) + + subgraph Workflow["CI/CD Workflow"] + Push[Git Push / PR Created] + Trigger{Gitea Actions
Workflow Trigger} + Queue[Job Queued] + + subgraph Runners["Self-Hosted Runners"] + Runner1[act_runner-1
systemd service] + Runner2[act_runner-2
systemd service] + end + + Pick{Runner
Available?} + Checkout[📥 Checkout Code] + Cache[💾 Setup Docker Cache] + Pull[📥 Pre-pull Test Images
postgres:18.4, nginx:1.27-alpine, alpine:3.19/3.20] + Test[🧪 Run Integration Tests
scripts/test-update.sh] + TestResult{Tests
Pass?} + Success[✅ Report Success
PR can merge] + Failure[❌ Report Failure
Upload test logs] + Artifact[📦 Upload Artifacts
7-day retention] + end + + Dev -->|git push| Push + Push --> Trigger + Trigger -->|PR to main| Queue + Trigger -->|workflow_dispatch| Queue + Queue --> Pick + Pick -->|Assigns Job| Runner1 + Pick -->|Assigns Job| Runner2 + Runner1 --> Checkout + Runner2 --> Checkout + Checkout --> Cache + Cache --> Pull + Pull --> Test + Test --> TestResult + TestResult -->|✅ All Pass| Success + TestResult -->|❌ Any Fail| Failure + Failure --> Artifact + + style Dev fill:#8B5CF6,stroke:#6D28D9,stroke-width:2px,color:#fff + style Push fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Trigger fill:#F97316,stroke:#C2410C,stroke-width:2px,color:#111827 + style Queue fill:#F59E0B,stroke:#B45309,stroke-width:2px,color:#111827 + style Pick fill:#F97316,stroke:#C2410C,stroke-width:2px,color:#111827 + style Runner1 fill:#EF4444,stroke:#B91C1C,stroke-width:2px,color:#fff + style Runner2 fill:#EF4444,stroke:#B91C1C,stroke-width:2px,color:#fff + style Checkout fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Cache fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Pull fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Test fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style TestResult fill:#F97316,stroke:#C2410C,stroke-width:2px,color:#111827 + style Success fill:#10B981,stroke:#047857,stroke-width:2px,color:#111827 + style Failure fill:#EF4444,stroke:#B91C1C,stroke-width:2px,color:#fff + style Artifact fill:#6366F1,stroke:#4338CA,stroke-width:2px,color:#fff +``` + +## Automated Setup Flow + +This diagram shows how the runner infrastructure is automatically provisioned and configured. + +```mermaid +%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#e5e7eb','primaryTextColor':'#111827','primaryBorderColor':'#9ca3af','lineColor':'#111827','secondaryColor':'#d1d5db','tertiaryColor':'#f3f4f6','edgeLabelBackground':'#ffffff','mainBkg':'#f5f5f4','nodeBorder':'#9ca3af','background':'#f5f5f4','clusterBkg':'transparent'},'themeCSS':'.node rect, .node circle, .node ellipse, .node polygon, .node path { filter: none !important; box-shadow: none !important; } .cluster rect { filter: none !important; box-shadow: none !important; } svg { background-color: #f5f5f4 !important; } .cluster-label { background-color: #ffffff !important; padding: 6px 12px !important; border-radius: 4px !important; font-size: 16px !important; font-weight: 700 !important; box-shadow: 0 1px 3px rgba(0,0,0,0.12) !important; border: 1px solid #d1d5db !important; } .edgePath, .edgePath path, .flowchart-link { z-index: 1 !important; }'}}%% + +flowchart TD + Start([Terraform Apply]) + Secrets[🔐 Create AWS Secrets
DB credentials, Admin credentials] + EC2[🖥️ Provision EC2 Instance
With IAM role for Secrets Manager] + + Ansible([Ansible Playbook]) + Deploy[📦 Deploy Gitea
docker-compose up] + Wait[⏳ Wait for Gitea
HTTP 200 response] + CreateUser[👤 Create Admin User
docker exec gitea gitea admin user create] + DisableChange[🔓 Disable Password Change
UPDATE user SET must_change_password=false] + GenToken[🎟️ Generate Runner Token
GET /api/v1/admin/runners/registration-token] + UpdateSecret[💾 Store Token in Secrets Manager
aws secretsmanager update-secret] + + DownloadRunner[📥 Download act_runner v0.2.10] + CreateDirs[📁 Create /etc/act_runner-{1,2}] + FetchToken[🔍 Fetch Runner Token
from Secrets Manager] + RegisterRunner[📝 Register Runners
act_runner register --instance http://localhost:3000] + CreateService[⚙️ Create systemd services
act_runner-1.service, act_runner-2.service] + StartService[▶️ Enable & Start Services] + + Complete([✅ Ready for CI/CD]) + + Start --> Secrets + Secrets --> EC2 + EC2 --> Ansible + + Ansible --> Deploy + Deploy --> Wait + Wait --> CreateUser + CreateUser --> DisableChange + DisableChange --> GenToken + GenToken --> UpdateSecret + + UpdateSecret --> DownloadRunner + DownloadRunner --> CreateDirs + CreateDirs --> FetchToken + FetchToken --> RegisterRunner + RegisterRunner --> CreateService + CreateService --> StartService + + StartService --> Complete + + style Start fill:#F59E0B,stroke:#B45309,stroke-width:2px,color:#111827 + style Secrets fill:#8B5CF6,stroke:#6D28D9,stroke-width:2px,color:#fff + style EC2 fill:#10B981,stroke:#047857,stroke-width:2px,color:#111827 + style Ansible fill:#F59E0B,stroke:#B45309,stroke-width:2px,color:#111827 + style Deploy fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Wait fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style CreateUser fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style DisableChange fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style GenToken fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style UpdateSecret fill:#8B5CF6,stroke:#6D28D9,stroke-width:2px,color:#fff + style DownloadRunner fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style CreateDirs fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style FetchToken fill:#8B5CF6,stroke:#6D28D9,stroke-width:2px,color:#fff + style RegisterRunner fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style CreateService fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style StartService fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#fff + style Complete fill:#10B981,stroke:#047857,stroke-width:2px,color:#111827 +``` + +## Workflow Configuration + +The CI/CD workflow is defined in `.gitea/workflows/test.yml`: + +```yaml +name: Integration Tests + +on: + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: ${{ runner.os }}-buildx- + + - name: Pre-pull test images + run: | + docker pull postgres:18.4 + docker pull nginx:1.27-alpine + docker pull alpine:3.19 + docker pull alpine:3.20 + + - name: Run integration tests + run: ./scripts/test-update.sh + + - name: Upload test logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: /tmp/test-*.log + retention-days: 7 +``` + +## Test Suite + +The `scripts/test-update.sh` integration test suite validates: + +1. **Static validation** (2 tests): + - Script syntax and linting + - Required executables available + +2. **Docker-based tests** (12 tests): + - PostgreSQL backup and restore + - Health check functionality + - Archive validation (SQL and tar formats) + - Update simulation workflow + - Container cleanup and resource management + +All tests must pass for a PR to be mergeable. + +## Key Features + +### Zero-Configuration CI/CD +- Runners automatically registered during initial deployment +- No manual token management needed +- Runner tokens stored securely in AWS Secrets Manager +- Complete automation from infrastructure provision to working CI/CD + +### High Availability +- 2 concurrent runners for parallel job execution +- Automatic job distribution by Gitea +- Systemd ensures runners restart on failure + +### Security +- Runners use local Gitea instance (`http://localhost:3000`) +- Admin credentials never exposed (CLI-based user creation) +- IAM roles for least-privilege access to AWS resources +- Runner tokens rotated on redeployment + +### Docker Optimization +- Docker layer caching for faster builds +- Image pre-pulling reduces test execution time +- Shared Docker daemon for all tests + +## Deployment Commands + +```bash +# Full deployment (includes runner setup) +make full-deploy + +# Update only configuration (re-registers runners if needed) +make configure + +# Run tests locally +make test +``` diff --git a/docs/diagrams/network-architecture.md b/docs/diagrams/network-architecture.md index e2e4f95..cba00b5 100644 --- a/docs/diagrams/network-architecture.md +++ b/docs/diagrams/network-architecture.md @@ -58,17 +58,19 @@ graph TB **EC2 Security Group**: - **Inbound Rules**: - Port 22 (SSH): From admin IP only (for management) - - Port 80 (HTTP): From 0.0.0.0/0 (redirects to HTTPS) - - Port 443 (HTTPS): From 0.0.0.0/0 (Gitea access) + - Port 80 (HTTP): From 0.0.0.0/0 (redirects to HTTPS, ACME challenge) + - Port 443 (HTTPS): From 0.0.0.0/0 (Gitea web access) + - Port 2222 (Git SSH): From 0.0.0.0/0 (Git push/pull via SSH) - **Outbound Rules**: - - All traffic: To 0.0.0.0/0 (for updates, backups to S3) + - All traffic: To 0.0.0.0/0 (for updates, backups to S3, Secrets Manager) ## Security Considerations 1. **SSH Access**: Restricted to specific admin IP address (your IP) 2. **HTTP/HTTPS**: Open to internet (required for Gitea web access) -3. **No Direct Gitea Access**: Port 3000 not exposed; only nginx on 80/443 -4. **Outbound**: Allowed for Docker image pulls, package updates, S3 backups +3. **Git SSH**: Port 2222 exposed for Git operations over SSH +4. **No Direct Gitea HTTP Access**: Port 3000 not exposed; only nginx on 80/443 +5. **Outbound**: Allowed for Docker image pulls, package updates, S3 backups, AWS API calls ## Traffic Flow