# Deploying Gitea with 1Password Secrets Management and Caddy on Bigbox **Date:** February 16, 2026 **Author:** Infrastructure Team **Tags:** gitea, 1password, caddy, docker, tailscale, devops ## Executive Summary This article documents the deployment of a production-ready Gitea instance on bigbox server, featuring enterprise-grade security with 1Password secrets management, Caddy reverse proxy with automatic HTTPS, and network isolation via Tailscale. ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ Internet │ │ │ │ │ ▼ │ │ ┌──────────────────────┐ │ │ │ Caddy (bigbox) │ │ │ │ :443/:80 │ │ │ └──────────┬───────────┘ │ │ │ │ │ ┌──────────────┼──────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ workflows. git.terraphim. *.terraphim. │ │ terraphim. cloud (NEW) cloud │ │ cloud │ (catchall) │ │ ▼ │ │ ┌──────────────┐ │ │ │ Gitea │ │ │ │ :3000 │ │ │ └──────┬───────┘ │ │ │ │ └───────────────────┼─────────────────────────────────────────────┘ │ ┌───────────┴───────────┐ │ Tailscale VPN │ │ (100.106.66.0/8) │ └───────────┬───────────┘ │ ┌───────────┼───────────┐ ▼ ▼ ▼ Prometheus S3 API SeaweedFS :9000 :8333 (Internal) ``` ## Key Features ### 1. Security-First Design - **No hardcoded secrets** - All credentials stored in 1Password - **1Password integration** - Secrets injected at runtime via `op inject` - **Template-based configuration** - `.template` files in git, resolved configs excluded - **Network isolation** - Internal services not exposed to internet ### 2. Multi-Layer Network Security | Service | Exposure | Access Method | |---------|----------|---------------| | Gitea Web | Public | HTTPS via Caddy (git.terraphim.cloud) | | Gitea SSH | Public | Port 222 direct | | Prometheus | Tailscale only | http://100.106.66.7:9000 | | S3 API | Tailscale only | http://100.106.66.7:8333 | | PostgreSQL | Internal only | Docker network | | SeaweedFS | Internal only | Docker network | ### 3. Technology Stack - **Gitea 1.22.6** - Git hosting with Actions support - **PostgreSQL 15** - Database - **SeaweedFS** - Distributed S3-compatible object storage - **Prometheus** - Metrics and monitoring - **Caddy** - Reverse proxy with automatic HTTPS - **1Password CLI** - Secrets management - **Tailscale** - VPN for internal services ## Deployment Process ### Prerequisites - SSH access to bigbox - 1Password service account configured (`~/op_zesticai_non_prod.sh`) - Caddy already running on bigbox - Docker and Docker Compose installed ### Step 1: Create 1Password Vault Items ```bash eval $(op signin) # Create PostgreSQL credentials op item create \ --vault="TerraphimPlatform" \ --category=login \ --title="gitea-postgres" \ --generate-password=20,letters,digits \ username=gitea # Create S3 credentials op item create \ --vault="TerraphimPlatform" \ --category=custom \ --title="gitea-s3" \ access-key="$(openssl rand -hex 20)" \ secret-key="$(openssl rand -hex 40)" ``` ### Step 2: Template Configuration Files Create `.template` files with 1Password references: **docker-compose.yml.template:** ```yaml version: "3" services: server: image: gitea/gitea:1.22.6 environment: - GITEA__database__PASSWD=op://TerraphimPlatform/gitea-postgres/password - GITEA__storage__MINIO_ACCESS_KEY_ID=op://TerraphimPlatform/gitea-s3/access-key - GITEA__storage__MINIO_SECRET_ACCESS_KEY=op://TerraphimPlatform/gitea-s3/secret-key # ... other config ``` **s3_config.json.template:** ```json { "identities": [{ "name": "gitea", "credentials": [{ "accessKey": "op://TerraphimPlatform/gitea-s3/access-key", "secretKey": "op://TerraphimPlatform/gitea-s3/secret-key" }] }] } ``` ### Step 3: Inject Secrets and Deploy ```bash # Source 1Password credentials source ~/op_zesticai_non_prod.sh # Inject secrets into configuration files op inject --in-file docker-compose.yml.template --out-file docker-compose.yml op inject --in-file s3_config.json.template --out-file s3_config.json # Start services docker compose up -d ``` ### Step 4: Configure Caddy Add Gitea route to existing Caddy instance: ```bash # Add route via Caddy Admin API curl -X POST http://localhost:2019/config/apps/http/servers/srv0/routes \ -H "Content-Type: application/json" \ -d '{ "@id": "gitea_route", "match": [{"host": ["git.terraphim.cloud"]}], "handle": [{ "handler": "subroute", "routes": [{ "handle": [{ "handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3000"}] }] }] }], "terminal": true }' ``` **Important:** Route order matters! Add specific routes before wildcard routes. ## Network Configuration Details ### Port Bindings **Gitea (Public):** - `127.0.0.1:3000:3000` - HTTP via Caddy - `0.0.0.0:222:22` - SSH direct access **Prometheus (Tailscale only):** - `100.106.66.7:9000:9090` - Only accessible via Tailscale **S3 API (Tailscale only):** - `100.106.66.7:8333:8333` - Only accessible via Tailscale - `100.106.66.7:9327:9327` - Prometheus metrics ### Docker Compose Network Isolation ```yaml networks: gitea: external: false # Internal Docker network only services: db: networks: - gitea # No external ports master: # No ports exposed - internal only volume: # No ports exposed - internal only filer: # No ports exposed - internal only ``` ## Security Considerations ### 1. Secrets Management - ✅ No secrets in Git repository - ✅ No secrets in Docker images - ✅ Secrets injected at runtime - ✅ Easy rotation via 1Password ### 2. Network Security - ✅ Public services behind Caddy with automatic HTTPS - ✅ Internal services on Tailscale VPN - ✅ Database isolated in Docker network - ✅ SSH on non-standard port (222) ### 3. Access Control - Prometheus and S3 require Tailscale connection - Gitea accessible publicly via HTTPS - SSH access available on port 222 ## Troubleshooting ### Permission Denied Errors If Gitea shows permission errors: ```bash sudo chown -R 1000:1000 gitea/ sudo chmod -R 755 gitea/ docker compose restart server ``` ### Route Not Working Check Caddy route order: ```bash curl -s http://localhost:2019/config/apps/http/servers/srv0/routes | \ jq '.[] | select(.match[0].host[0] | contains("terraphim")) | .match[0].host[0]' ``` Specific routes must come before wildcard routes. ### 1Password Authentication Verify service account: ```bash source ~/op_zesticai_non_prod.sh op vault list ``` ## Maintenance ### Backup ```bash # Backup data directories rsync -avz bigbox:~/gitea-stack/gitea ./backup/ rsync -avz bigbox:~/gitea-stack/postgres ./backup/ rsync -avz bigbox:~/gitea-stack/seaweedfs ./backup/ ``` ### Update Images ```bash cd ~/gitea-stack docker compose pull docker compose up -d ``` ### Rotate Secrets 1. Update in 1Password vault 2. Re-run deployment: ```bash source ~/op_zesticai_non_prod.sh op inject --in-file docker-compose.yml.template --out-file docker-compose.yml docker compose up -d ``` ## Access Points ### Public URLs - **Gitea Web:** https://git.terraphim.cloud - **Gitea SSH:** ssh://git@bigbox:222 ### Tailscale-only URLs Connect to Tailscale first: `tailscale up` - **Prometheus:** http://100.106.66.7:9000 - **S3 API:** http://100.106.66.7:8333 ## Conclusion This deployment demonstrates production-ready practices: - Zero hardcoded secrets - Defense in depth with network isolation - Automatic HTTPS via Caddy - Easy maintenance with Docker Compose - Centralized secrets management with 1Password The architecture balances security (Tailscale isolation, 1Password integration) with usability (public HTTPS access to Gitea, direct SSH access). ## References - [Gitea Documentation](https://docs.gitea.io/) - [1Password CLI](https://developer.1password.com/docs/cli/) - [Caddy Documentation](https://caddyserver.com/docs/) - [Tailscale](https://tailscale.com/) --- **Repository:** [Private terraphim repo with configuration]