From 49fe96775a6fe9291cec651b7d37dd63d9ed4959 Mon Sep 17 00:00:00 2001 From: kappa Date: Fri, 16 Jan 2026 00:39:06 +0900 Subject: [PATCH] Add 5 more runbooks - aws-ses-setup.md: AWS SES email configuration - anvil-ses-final-setup.md: Anvil SES final setup - n8n-setup-guide.md: n8n workflow automation - gitea-setup.md: Gitea server installation - cloudflare-vault-integration.md: Cloudflare + Vault integration Co-Authored-By: Claude Opus 4.5 --- README.md | 14 + anvil-ses-final-setup.md | 195 +++++++++++ aws-ses-setup.md | 271 ++++++++++++++++ cloudflare-vault-integration.md | 69 ++++ gitea-setup.md | 552 ++++++++++++++++++++++++++++++++ n8n-setup-guide.md | 273 ++++++++++++++++ 6 files changed, 1374 insertions(+) create mode 100644 anvil-ses-final-setup.md create mode 100644 aws-ses-setup.md create mode 100644 cloudflare-vault-integration.md create mode 100644 gitea-setup.md create mode 100644 n8n-setup-guide.md diff --git a/README.md b/README.md index e6a36cf..6e8757c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ DevOps 운영 매뉴얼 및 기술 가이드 모음 | [kitty-setup-guide.md](kitty-setup-guide.md) | Kitty 터미널 설정 가이드 | | [claude_communication_flow.md](claude_communication_flow.md) | Claude 통신 흐름 문서 | | [anvil-load-test-report.md](anvil-load-test-report.md) | Anvil 부하 테스트 리포트 | +| [aws-ses-setup.md](aws-ses-setup.md) | AWS SES 이메일 설정 | +| [anvil-ses-final-setup.md](anvil-ses-final-setup.md) | Anvil SES 최종 설정 | +| [n8n-setup-guide.md](n8n-setup-guide.md) | n8n 워크플로우 자동화 설정 | +| [gitea-setup.md](gitea-setup.md) | Gitea Git 서버 설치 및 설정 | +| [cloudflare-vault-integration.md](cloudflare-vault-integration.md) | Cloudflare + Vault 연동 | ## 카테고리 @@ -26,6 +31,15 @@ DevOps 운영 매뉴얼 및 기술 가이드 모음 ### 인프라 - incus-meilisearch-manual.md - anvil-load-test-report.md +- gitea-setup.md + +### 이메일 +- aws-ses-setup.md +- anvil-ses-final-setup.md + +### 자동화 +- n8n-setup-guide.md +- cloudflare-vault-integration.md ### 개발 환경 - kitty-setup-guide.md diff --git a/anvil-ses-final-setup.md b/anvil-ses-final-setup.md new file mode 100644 index 0000000..e428782 --- /dev/null +++ b/anvil-ses-final-setup.md @@ -0,0 +1,195 @@ +# AWS SES 완벽 설정 완료 - anvil.it.com + +## 🎉 설정 완료 상태 +**Mail-Tester 점수: 10/10 (만점)** ✅ + +설정 완료일: 2025-09-06 +도메인: anvil.it.com +리전: ap-northeast-2 (Seoul) + +## 📧 SMTP 설정 정보 + +```yaml +SMTP_HOST: email-smtp.ap-northeast-2.amazonaws.com +SMTP_PORT: 587 +SMTP_TLS: true +SMTP_USERNAME: [Vault: secret/aws/ses/smtp -> smtp_username] +SMTP_PASSWORD: [Vault: secret/aws/ses/smtp -> smtp_password] +SMTP_FROM: noreply@anvil.it.com +``` + +### Vault에서 인증 정보 조회 +```bash +# 전체 설정 조회 +vault kv get secret/aws/ses/smtp + +# SMTP Password만 조회 +vault kv get -field=smtp_password secret/aws/ses/smtp +``` + +## 🔐 DNS 레코드 설정 + +### 1. SPF 레코드 (TXT) +``` +anvil.it.com TXT "v=spf1 include:_spf.mx.cloudflare.net include:amazonses.com ~all" +``` + +### 2. DKIM 레코드 (CNAME × 3) +``` +dgcehnldehfmfgpvrrbc6drwasiibhnp._domainkey.anvil.it.com CNAME dgcehnldehfmfgpvrrbc6drwasiibhnp.dkim.amazonses.com +spopdscdt2sxngqzl5ir66k3ed6og7ut._domainkey.anvil.it.com CNAME spopdscdt2sxngqzl5ir66k3ed6og7ut.dkim.amazonses.com +55l5wnmktvacgyfpt6sovcgb2rqexrpy._domainkey.anvil.it.com CNAME 55l5wnmktvacgyfpt6sovcgb2rqexrpy.dkim.amazonses.com +``` + +### 3. DMARC 레코드 (TXT) +``` +_dmarc.anvil.it.com TXT "v=DMARC1;p=quarantine;pct=25;rua=mailto:908761dcafa547a981e283a21768d69f@dmarc-reports.cloudflare.net,mailto:dmarc-reports@anvil.it.com;ruf=mailto:dmarc-failures@anvil.it.com" +``` + +### 4. MAIL FROM 도메인 설정 +``` +# MX 레코드 +bounce.anvil.it.com MX 10 feedback-smtp.ap-northeast-2.amazonses.com + +# SPF 레코드 +bounce.anvil.it.com TXT "v=spf1 include:amazonses.com ~all" +``` + +### 5. 도메인 검증 (TXT) +``` +_amazonses.anvil.it.com TXT "0cuw9v32N+aeFiNlTh2Poxglgzf3BlmFRjVOjeLEdy4=" +``` + +## ✅ AWS SES 상태 + +### 도메인 검증 +- **Status**: Success ✅ +- **DKIM**: Success & Enabled ✅ +- **MAIL FROM**: bounce.anvil.it.com (Success) ✅ + +### 발송 한도 +- **일일 최대**: 50,000통 +- **초당 최대**: 14통 +- **현재 환경**: Production Ready + +## 🎯 컴플라이언스 달성 상태 + +| 요구사항 | 상태 | 점수 | +|---------|------|------| +| SPF Authentication | ✅ Compliant | Pass | +| DKIM Authentication | ✅ Compliant | Pass | +| DMARC Authentication | ✅ Quarantine (25%) | Pass | +| From Header Alignment | ✅ Compliant | Pass | +| DNS Records | ✅ Compliant | Pass | +| Encryption | ✅ TLS Required | Pass | +| One-click Unsubscribe | ✅ RFC 8058 | Pass | +| Honor Unsubscribe | ✅ Compliant | Pass | + +**최종 점수: 8/8 (완전 준수)** 🏆 + +## 📱 애플리케이션 통합 예시 + +### Node.js (nodemailer) +```javascript +const nodemailer = require('nodemailer'); + +const transporter = nodemailer.createTransporter({ + host: 'email-smtp.ap-northeast-2.amazonaws.com', + port: 587, + secure: false, + auth: { + user: process.env.SMTP_USERNAME, // SMTP Username + pass: process.env.SMTP_PASSWORD // SMTP Password (변환된 값) + } +}); + +// RFC 8058 호환 메일 발송 +const mailOptions = { + from: 'noreply@anvil.it.com', + to: 'user@example.com', + subject: 'Welcome!', + html: '

Welcome!

', + headers: { + 'List-Unsubscribe': ', ', + 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click' + } +}; +``` + +### Python (smtplib) +```python +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +msg = MIMEMultipart() +msg['From'] = 'noreply@anvil.it.com' +msg['To'] = 'user@example.com' +msg['Subject'] = 'Welcome!' +msg['List-Unsubscribe'] = ', ' +msg['List-Unsubscribe-Post'] = 'List-Unsubscribe=One-Click' + +server = smtplib.SMTP('email-smtp.ap-northeast-2.amazonaws.com', 587) +server.starttls() +server.login(smtp_username, smtp_password) +server.send_message(msg) +server.quit() +``` + +## 🚀 성과 요약 + +1. **완벽한 인증 체계**: SPF, DKIM, DMARC 모두 통과 +2. **최고 수준 컴플라이언스**: RFC 8058 One-click Unsubscribe 구현 +3. **Gmail 최적화**: Postmaster Tools 준비 완료 +4. **확장 가능한 구조**: 일일 50K 발송 지원 +5. **보안 강화**: 단계적 DMARC 정책 (quarantine 25%) + +## 📊 모니터링 및 관리 + +### Gmail Postmaster Tools +- URL: https://postmaster.google.com +- 도메인 등록: anvil.it.com +- 데이터 확인: 1-2일 후부터 + +### DMARC 리포트 +- **집계 리포트**: dmarc-reports@anvil.it.com +- **실패 리포트**: dmarc-failures@anvil.it.com +- **Cloudflare**: 자동 대시보드 제공 + +### AWS SES 모니터링 +```bash +# 발송 통계 +aws ses get-send-statistics --region ap-northeast-2 + +# 발송 한도 확인 +aws ses get-send-quota --region ap-northeast-2 +``` + +## 🔄 향후 개선 계획 + +### 1단계 (완료): 기본 설정 +- ✅ 도메인 검증 +- ✅ DKIM 활성화 +- ✅ SPF 설정 +- ✅ DMARC 모니터링 + +### 2단계 (완료): 컴플라이언스 +- ✅ DMARC quarantine (25%) +- ✅ One-click Unsubscribe +- ✅ RFC 8058 준수 + +### 3단계 (2주 후): 정책 강화 +- DMARC: p=quarantine;pct=100 +- 평판 안정화 후 p=reject 고려 +- Gmail Postmaster 데이터 분석 + +### 4단계 (1개월 후): 고도화 +- 발송량 점진적 증가 (Warm-up) +- A/B 테스트 기반 최적화 +- 고급 모니터링 구축 + +--- + +**🎯 결과: anvil.it.com 메일 시스템은 업계 최고 수준으로 설정되었습니다!** + +Mail-Tester 10/10 점수는 모든 주요 메일 서비스에서 anvil.it.com을 신뢰할 수 있는 발신자로 인식한다는 의미입니다. \ No newline at end of file diff --git a/aws-ses-setup.md b/aws-ses-setup.md new file mode 100644 index 0000000..5da7b7a --- /dev/null +++ b/aws-ses-setup.md @@ -0,0 +1,271 @@ +# AWS SES 메일 발송 설정 가이드 + +> 작성일: 2026-01-12 +> 리전: ap-northeast-2 (서울) + +## 개요 + +AWS SES(Simple Email Service)를 사용하여 서버에서 메일을 발송하기 위한 설정 가이드입니다. + +--- + +## 계정 상태 + +| 항목 | 값 | +|------|-----| +| 리전 | ap-northeast-2 (서울) | +| 모드 | **프로덕션** (샌드박스 해제됨) | +| 24시간 발송 한도 | 50,000통 | +| 초당 발송률 | 14통/초 | + +--- + +## 인증된 도메인 + +| 도메인 | 도메인 인증 | DKIM | +|--------|------------|------| +| `anvil.it.com` | ✅ Success | ✅ Success | +| `ironclad.it.com` | ✅ Success | ✅ Success | + +### 사용 가능한 발신자 주소 + +``` +*@anvil.it.com (예: noreply@anvil.it.com, support@anvil.it.com) +*@ironclad.it.com (예: noreply@ironclad.it.com, admin@ironclad.it.com) +``` + +--- + +## DNS 설정 (Cloudflare) + +### anvil.it.com + +**TXT 레코드 (도메인 소유권 확인)** +| Type | Name | Content | +|------|------|---------| +| TXT | `_amazonses.anvil.it.com` | `0cuw9v32N+aeFiNlTh2Poxglgzf3BlmFRjVOjeLEdy4=` | + +**CNAME 레코드 (DKIM)** +| Type | Name | Target | +|------|------|--------| +| CNAME | `dgcehnldehfmfgpvrrbc6drwasiibhnp._domainkey` | `dgcehnldehfmfgpvrrbc6drwasiibhnp.dkim.amazonses.com` | +| CNAME | `spopdscdt2sxngqzl5ir66k3ed6og7ut._domainkey` | `spopdscdt2sxngqzl5ir66k3ed6og7ut.dkim.amazonses.com` | +| CNAME | `55l5wnmktvacgyfpt6sovcgb2rqexrpy._domainkey` | `55l5wnmktvacgyfpt6sovcgb2rqexrpy.dkim.amazonses.com` | + +### ironclad.it.com + +**TXT 레코드 (도메인 소유권 확인)** +| Type | Name | Content | +|------|------|---------| +| TXT | `_amazonses.ironclad.it.com` | `C+RMHyLd/U2H5WSCu8L2avRn8NmuwEll0xxYjTyvoEY=` | + +**CNAME 레코드 (DKIM)** +| Type | Name | Target | +|------|------|--------| +| CNAME | `5sycmzu364y2rgefnqaloptgodymasct._domainkey` | `5sycmzu364y2rgefnqaloptgodymasct.dkim.amazonses.com` | +| CNAME | `qm7d7qgkdikpcbrbgo7bmgqfmuulrbah._domainkey` | `qm7d7qgkdikpcbrbgo7bmgqfmuulrbah.dkim.amazonses.com` | +| CNAME | `tu6oey5tktoqub753cxpayhhwrlzcskk._domainkey` | `tu6oey5tktoqub753cxpayhhwrlzcskk.dkim.amazonses.com` | + +--- + +## IAM 권한 설정 + +### 최소 권한 정책 (권장) + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "SESSendEmail", + "Effect": "Allow", + "Action": [ + "ses:SendEmail", + "ses:SendRawEmail" + ], + "Resource": "*" + } + ] +} +``` + +### 특정 발신자 제한 정책 + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "SESSendFromVerified", + "Effect": "Allow", + "Action": [ + "ses:SendEmail", + "ses:SendRawEmail" + ], + "Resource": [ + "arn:aws:ses:ap-northeast-2:*:identity/anvil.it.com", + "arn:aws:ses:ap-northeast-2:*:identity/ironclad.it.com" + ] + } + ] +} +``` + +--- + +## 사용 방법 + +### AWS CLI + +```bash +aws ses send-email \ + --from "noreply@anvil.it.com" \ + --to "recipient@example.com" \ + --subject "메일 제목" \ + --text "메일 본문" \ + --region ap-northeast-2 +``` + +### Python (boto3) + +```python +import boto3 +from botocore.exceptions import ClientError + +def send_email(to_email: str, subject: str, body: str, sender: str = "noreply@anvil.it.com"): + client = boto3.client('ses', region_name='ap-northeast-2') + + try: + response = client.send_email( + Source=sender, + Destination={'ToAddresses': [to_email]}, + Message={ + 'Subject': {'Data': subject, 'Charset': 'UTF-8'}, + 'Body': { + 'Text': {'Data': body, 'Charset': 'UTF-8'}, + # HTML 본문 사용 시: + # 'Html': {'Data': '

Hello

', 'Charset': 'UTF-8'} + } + } + ) + print(f"발송 완료: {response['MessageId']}") + return response + except ClientError as e: + print(f"발송 실패: {e.response['Error']['Message']}") + raise + +# 사용 예시 +send_email( + to_email='recipient@example.com', + subject='테스트 메일', + body='안녕하세요!' +) +``` + +### Python (HTML 메일) + +```python +def send_html_email(to_email: str, subject: str, html_body: str, text_body: str = None): + client = boto3.client('ses', region_name='ap-northeast-2') + + body = {'Html': {'Data': html_body, 'Charset': 'UTF-8'}} + if text_body: + body['Text'] = {'Data': text_body, 'Charset': 'UTF-8'} + + response = client.send_email( + Source='noreply@anvil.it.com', + Destination={'ToAddresses': [to_email]}, + Message={ + 'Subject': {'Data': subject, 'Charset': 'UTF-8'}, + 'Body': body + } + ) + return response + +# 사용 예시 +html = """ + + +

안녕하세요!

+

AWS SES로 발송된 HTML 메일입니다.

+ + +""" +send_html_email('recipient@example.com', '테스트', html) +``` + +--- + +## 환경변수 설정 (컨테이너용) + +```bash +export AWS_ACCESS_KEY_ID="your_access_key" +export AWS_SECRET_ACCESS_KEY="your_secret_key" +export AWS_DEFAULT_REGION="ap-northeast-2" +``` + +환경변수 설정 시 코드에서 자격증명 생략 가능: + +```python +client = boto3.client('ses') # 환경변수에서 자동 로드 +``` + +--- + +## 상태 확인 명령어 + +```bash +# 발송 활성화 상태 +aws ses get-account-sending-enabled + +# 발송 한도 확인 +aws ses get-send-quota + +# 등록된 Identity 목록 +aws ses list-identities + +# 도메인 인증 상태 +aws ses get-identity-verification-attributes --identities anvil.it.com ironclad.it.com + +# DKIM 상태 +aws ses get-identity-dkim-attributes --identities anvil.it.com ironclad.it.com +``` + +--- + +## 새 도메인 추가 방법 + +### 1. SES 도메인 등록 + +```bash +aws ses verify-domain-identity --domain newdomain.com +aws ses verify-domain-dkim --domain newdomain.com +``` + +### 2. Cloudflare DNS 레코드 추가 + +출력된 토큰으로 TXT, CNAME 레코드 추가 (Cloudflare API 또는 대시보드) + +### 3. 인증 확인 + +```bash +aws ses get-identity-verification-attributes --identities newdomain.com +aws ses get-identity-dkim-attributes --identities newdomain.com +``` + +--- + +## 참고 사항 + +- **프로덕션 모드**: 수신자 제한 없음 +- **DKIM**: 메일 신뢰도 향상 (스팸 방지) +- **발송 한도**: 필요시 AWS에 증가 요청 가능 +- **비용**: $0.10 / 1,000통 + +--- + +## 관련 링크 + +- [AWS SES 콘솔](https://ap-northeast-2.console.aws.amazon.com/ses/) +- [AWS SES 개발자 가이드](https://docs.aws.amazon.com/ses/latest/dg/) +- [Cloudflare DNS](https://dash.cloudflare.com/) diff --git a/cloudflare-vault-integration.md b/cloudflare-vault-integration.md new file mode 100644 index 0000000..4506666 --- /dev/null +++ b/cloudflare-vault-integration.md @@ -0,0 +1,69 @@ +# Cloudflare Vault 통합 가이드 + +## 저장 방식 권장사항 + +### 1. **API Token 방식 (권장)** +```bash +# Vault에 저장 +vault kv put secret/cloudflare/tokens \ + api_token="your-api-token" \ + account_id="your-account-id" + +# 사용 +export CLOUDFLARE_API_TOKEN=$(vault kv get -field=api_token secret/cloudflare/tokens) +``` + +### 2. **Global API Key 방식 (현재)** +```bash +# 현재 Vault 구조 +secret/cloudflare/ + ├── email + └── api_key + +# 사용 +export CF_API_EMAIL=$(vault kv get -field=email secret/cloudflare) +export CF_API_KEY=$(vault kv get -field=api_key secret/cloudflare) +``` + +### 3. **Tunnel 별 크레덴셜** +```bash +# Vault에 터널별로 저장 +vault kv put secret/cloudflare/tunnels/production \ + tunnel_id="uuid" \ + tunnel_secret="base64-secret" \ + account_id="account-id" + +# JSON 파일로 추출 +vault kv get -format=json secret/cloudflare/tunnels/production | \ + jq '.data.data' > ~/.cloudflared/production.json +``` + +## 자동화 스크립트 + +### Fish Shell 함수 +```fish +function cf-auth + set -gx CF_API_EMAIL (vault kv get -field=email secret/cloudflare) + set -gx CF_API_KEY (vault kv get -field=api_key secret/cloudflare) + echo "Cloudflare 인증 설정 완료" +end +``` + +### Bash 별칭 +```bash +alias cf-auth='eval $(vault kv get -format=json secret/cloudflare | jq -r ".data.data | to_entries[] | \"export CF_\" + (.key | ascii_upcase) + \"=\" + .value")' +``` + +## 보안 고려사항 + +1. **최소 권한 원칙**: API Token 사용 시 필요한 권한만 부여 +2. **임시 인증**: 환경변수는 세션 종료 시 자동 삭제 +3. **파일 권한**: `chmod 600 ~/.cloudflared/*` +4. **Vault 통합**: 모든 크레덴셜은 Vault에서 중앙 관리 + +## 추천 워크플로우 + +1. Vault에 API Token 저장 (Global Key 대신) +2. 필요시 환경변수로 로드 +3. 작업 완료 후 환경변수 정리 +4. CI/CD에서는 Vault Agent 사용 \ No newline at end of file diff --git a/gitea-setup.md b/gitea-setup.md new file mode 100644 index 0000000..09e5e4b --- /dev/null +++ b/gitea-setup.md @@ -0,0 +1,552 @@ +# Gitea Docker Compose Setup + +A production-ready Gitea deployment using Docker Compose with PostgreSQL, optimized for NAS systems and self-hosted environments. + +## 🚀 Quick Start + +1. **Clone or download this repository** +2. **Run the setup script:** + ```bash + ./setup-gitea.sh + ``` +3. **Start Gitea:** + ```bash + docker-compose up -d + ``` +4. **Access Gitea at:** `http://localhost:3000` + +## 📋 Prerequisites + +### Required Software +- **Docker Engine** (20.10+) +- **Docker Compose** (2.0+) +- **OpenSSL** (for generating secure keys) +- **Bash** (for setup scripts) + +### System Requirements +- **RAM:** Minimum 2GB, recommended 4GB+ +- **Storage:** Minimum 10GB free space +- **Network:** Ports 3000 (HTTP) and 2222 (SSH) available + +### Installation Commands + +**Ubuntu/Debian:** +```bash +# Install Docker +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh +sudo usermod -aG docker $USER + +# Install Docker Compose +sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +sudo chmod +x /usr/local/bin/docker-compose + +# Log out and back in to apply group changes +``` + +**macOS:** +```bash +# Install Docker Desktop from https://docker.com/products/docker-desktop +# Or via Homebrew: +brew install --cask docker +``` + +## 🏗️ Architecture + +### Services +- **gitea**: Main Gitea application (rootless container) +- **gitea-db**: PostgreSQL 15 database +- **gitea-runner**: Optional Gitea Actions runner + +### Volumes +- **gitea-data**: Application data and repositories +- **gitea-config**: Configuration files +- **gitea-db-data**: PostgreSQL data +- **gitea-runner-data**: Actions runner data + +### Network +- **gitea-network**: Isolated bridge network with custom subnet + +## ⚙️ Configuration + +### Environment Variables + +The setup is configured through a `.env` file. Key settings include: + +```bash +# Domain Configuration +GITEA_DOMAIN=your-domain.com +GITEA_ROOT_URL=https://your-domain.com + +# Port Configuration +GITEA_HTTP_PORT=3000 +GITEA_SSH_PORT=2222 + +# Security (automatically generated) +GITEA_SECRET_KEY=your_secret_key +GITEA_INTERNAL_TOKEN=your_internal_token + +# Database +POSTGRES_PASSWORD=secure_password + +# Admin Account +GITEA_ADMIN_USER=admin +GITEA_ADMIN_EMAIL=admin@your-domain.com +GITEA_ADMIN_PASSWORD=secure_password +``` + +### Advanced Configuration + +For advanced settings, modify: +- **docker-compose.yml**: Service configuration, resource limits, environment variables +- **gitea-app.ini.template**: Detailed Gitea configuration reference +- **.env**: Environment-specific settings + +## 🚀 Installation Guide + +### Method 1: Automated Setup (Recommended) + +```bash +# 1. Download the setup files +git clone gitea-setup +cd gitea-setup + +# 2. Run interactive setup +./setup-gitea.sh + +# 3. Start services +docker-compose up -d + +# 4. Check status +docker-compose ps +docker-compose logs -f gitea +``` + +### Method 2: Manual Setup + +```bash +# 1. Create directories +mkdir -p gitea-{data,config,db-data,runner-data} backups + +# 2. Copy environment file +cp .env.example .env + +# 3. Edit configuration +nano .env # Update all required values + +# 4. Generate secure keys +openssl rand -base64 32 # Use for GITEA_SECRET_KEY +openssl rand -base64 32 # Use for GITEA_INTERNAL_TOKEN + +# 5. Start services +docker-compose up -d +``` + +## 🔐 Security Configuration + +### SSL/TLS Setup with Reverse Proxy + +**Nginx Configuration:** +```nginx +server { + listen 80; + server_name your-domain.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name your-domain.com; + + ssl_certificate /path/to/certificate.crt; + ssl_certificate_key /path/to/private.key; + + client_max_body_size 512M; + + location / { + proxy_pass http://localhost: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; + } +} +``` + +**Traefik Configuration:** +```yaml +# docker-compose.override.yml +services: + gitea: + labels: + - "traefik.enable=true" + - "traefik.http.routers.gitea.rule=Host(`your-domain.com`)" + - "traefik.http.routers.gitea.tls.certresolver=letsencrypt" + - "traefik.http.services.gitea.loadbalancer.server.port=3000" +``` + +### SSH Configuration + +**Host SSH Configuration (recommended):** +```bash +# Add to /etc/ssh/sshd_config +Match User git + AllowTcpForwarding no + AllowAgentForwarding no + PermitTTY no + X11Forwarding no +``` + +**Container SSH (current setup):** +- SSH server runs inside Gitea container +- Exposed on port 2222 +- User authentication via Gitea SSH keys + +### Firewall Configuration + +```bash +# Ubuntu/Debian (ufw) +sudo ufw allow 3000/tcp comment 'Gitea HTTP' +sudo ufw allow 2222/tcp comment 'Gitea SSH' + +# CentOS/RHEL (firewalld) +sudo firewall-cmd --permanent --add-port=3000/tcp +sudo firewall-cmd --permanent --add-port=2222/tcp +sudo firewall-cmd --reload +``` + +## 🗄️ Backup & Restore + +### Automated Backup + +```bash +# Full backup (recommended) +./backup-gitea.sh --full + +# Database only +./backup-gitea.sh --database-only + +# Custom retention and compression +./backup-gitea.sh --full --retention 90 --compress 9 +``` + +### Backup Schedule + +**Crontab example:** +```bash +# Daily backup at 2 AM, keep for 30 days +0 2 * * * /path/to/gitea-setup/backup-gitea.sh --full --retention 30 + +# Weekly full backup, keep for 1 year +0 2 * * 0 /path/to/gitea-setup/backup-gitea.sh --full --retention 365 +``` + +### Restore from Backup + +```bash +# Restore from full backup +./restore-gitea.sh backups/gitea_backup_20240101_120000.tar.gz + +# Restore database only +./restore-gitea.sh --database-only backup_directory/ + +# Restore with current data backup +./restore-gitea.sh --backup-current latest_backup.tar.gz +``` + +## 🔄 Maintenance + +### Update Gitea + +```bash +# Check for updates +./update-gitea.sh --check-only + +# Update to latest version +./update-gitea.sh + +# Update to specific version +./update-gitea.sh 1.21.5 +``` + +### Monitor Services + +```bash +# Check service status +docker-compose ps + +# View logs +docker-compose logs -f gitea +docker-compose logs -f gitea-db + +# Monitor resources +docker-compose top +docker stats +``` + +### Database Maintenance + +```bash +# Access database +docker-compose exec gitea-db psql -U gitea -d gitea + +# Database backup +docker-compose exec gitea-db pg_dump -U gitea -d gitea > backup.sql + +# Database restore +docker-compose exec -T gitea-db psql -U gitea -d gitea < backup.sql +``` + +## 🔧 Troubleshooting + +### Common Issues + +**1. Permission Errors** +```bash +# Fix directory permissions +sudo chown -R 1000:1000 gitea-data gitea-config +sudo chmod -R 755 gitea-data gitea-config +``` + +**2. Database Connection Issues** +```bash +# Check database logs +docker-compose logs gitea-db + +# Test database connection +docker-compose exec gitea-db pg_isready -U gitea -d gitea +``` + +**3. SSH Access Issues** +```bash +# Check SSH configuration +docker-compose exec gitea cat /etc/gitea/app.ini | grep -A 5 "\[server\]" + +# Test SSH connection +ssh -T git@localhost -p 2222 +``` + +**4. Memory/Resource Issues** +```bash +# Check resource usage +docker stats + +# Adjust resource limits in docker-compose.yml +services: + gitea: + deploy: + resources: + limits: + memory: 2G + cpus: '1.0' +``` + +### Log Analysis + +```bash +# Application logs +docker-compose logs --tail=100 -f gitea + +# Database logs +docker-compose logs --tail=100 -f gitea-db + +# System logs (Ubuntu/Debian) +sudo journalctl -u docker --tail=100 -f +``` + +### Health Checks + +```bash +# Service health +docker-compose exec gitea curl -f http://localhost:3000/api/healthz + +# Database health +docker-compose exec gitea-db pg_isready -U gitea -d gitea +``` + +## 🎯 Performance Optimization + +### NAS-Specific Optimizations + +**1. Storage Configuration:** +```yaml +# Use external SSD for better performance +volumes: + gitea-data: + driver: local + driver_opts: + type: none + o: bind + device: /mnt/ssd/gitea-data +``` + +**2. Resource Limits:** +```yaml +services: + gitea: + deploy: + resources: + limits: + memory: 1G + cpus: '1.0' + reservations: + memory: 512M + cpus: '0.5' +``` + +**3. Database Tuning:** +```bash +# Add to docker-compose.yml under gitea-db environment +POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C" +``` + +### Network Optimization + +```yaml +# Custom network configuration +networks: + gitea-network: + driver: bridge + ipam: + config: + - subnet: 172.20.0.0/16 +``` + +## 📊 Monitoring + +### Basic Monitoring + +```bash +# Resource usage +docker stats --no-stream + +# Disk usage +du -sh gitea-data/ gitea-db-data/ + +# Service health +curl -f http://localhost:3000/api/healthz +``` + +### Advanced Monitoring with Prometheus + +```yaml +# Add to docker-compose.yml + prometheus: + image: prom/prometheus:latest + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + + grafana: + image: grafana/grafana:latest + ports: + - "3001:3000" + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin +``` + +## 🔌 Gitea Actions (CI/CD) + +### Enable Actions Runner + +```bash +# Start with actions profile +docker-compose --profile actions up -d + +# Or enable in existing deployment +docker-compose up -d gitea-runner +``` + +### Runner Configuration + +1. **Generate Registration Token:** + - Go to Gitea Admin → Site Administration → Actions → Runners + - Click "Create new Runner" + - Copy the registration token + +2. **Add Token to Environment:** + ```bash + echo "GITEA_RUNNER_TOKEN=your_token_here" >> .env + docker-compose restart gitea-runner + ``` + +### Action Examples + +**.gitea/workflows/ci.yml:** +```yaml +name: CI +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run tests + run: | + echo "Running tests..." + # Add your test commands here +``` + +## 📚 Additional Resources + +### Official Documentation +- [Gitea Documentation](https://docs.gitea.com/) +- [Docker Compose Reference](https://docs.docker.com/compose/) +- [PostgreSQL Documentation](https://www.postgresql.org/docs/) + +### Community Resources +- [Gitea Community](https://github.com/go-gitea/gitea/discussions) +- [Docker Community](https://forums.docker.com/) + +### Migration Guides +- [GitHub to Gitea Migration](https://docs.gitea.com/usage/migrate-from-github/) +- [GitLab to Gitea Migration](https://docs.gitea.com/usage/migrate-from-gitlab/) + +## 🆘 Support + +### Getting Help + +1. **Check logs first:** + ```bash + docker-compose logs -f gitea + ``` + +2. **Review common issues** in this README + +3. **Search existing issues:** + - [Gitea Issues](https://github.com/go-gitea/gitea/issues) + - [Community Discussions](https://github.com/go-gitea/gitea/discussions) + +4. **Create detailed bug report** with: + - Gitea version + - Docker version + - Operating system + - Error logs + - Steps to reproduce + +### Script Help + +All scripts include built-in help: +```bash +./setup-gitea.sh --help +./backup-gitea.sh --help +./restore-gitea.sh --help +./update-gitea.sh --help +``` + +## 📄 License + +This setup configuration is provided under the MIT License. Gitea itself is licensed under the MIT License. + +## 🙏 Acknowledgments + +- [Gitea Team](https://gitea.io/) for creating an excellent Git service +- [Docker Community](https://docker.com/) for containerization platform +- [PostgreSQL Team](https://postgresql.org/) for the reliable database + +--- + +**Happy Self-Hosting!** 🎉 + +For questions or improvements, please open an issue or pull request. \ No newline at end of file diff --git a/n8n-setup-guide.md b/n8n-setup-guide.md new file mode 100644 index 0000000..e7f131a --- /dev/null +++ b/n8n-setup-guide.md @@ -0,0 +1,273 @@ +# 🤖 n8n AI Agent: Cloudflare Tunnel 자동화 가이드 + +n8n에서 Cloudflare Tunnel과 Nginx Proxy Manager를 자동으로 설정하는 AI 에이전트 워크플로우입니다. + +## 🏗️ 아키텍처 + +```mermaid +graph TD + A[HTTP Request] --> B[n8n Webhook] + B --> C[AI Agent 검증] + C --> D[Cloudflare API] + C --> E[NPM API] + D --> F[DNS CNAME 설정] + E --> G[프록시 호스트 생성] + F --> H[완료 응답] + G --> H +``` + +## 📋 사전 요구사항 + +### 1. n8n 설치 및 실행 +```bash +# Docker Compose로 실행 (권장) +docker run -it --rm --name n8n -p 5678:5678 n8nio/n8n + +# 또는 npm으로 설치 +npm install n8n -g +n8n start +``` + +### 2. Credentials 설정 +n8n에서 다음 Credentials를 생성해야 합니다: + +#### Cloudflare Credential (`cloudflare`) +```json +{ + "email": "your-email@example.com", + "api_key": "your-global-api-key" +} +``` + +#### NPM Credential (`npm`) - 선택사항 +```json +{ + "url": "http://localhost:81", + "email": "admin@example.com", + "password": "changeme" +} +``` + +## 🚀 워크플로우 설치 + +### 1. 메인 AI Agent 워크플로우 임포트 +1. n8n 대시보드에서 **"Import from file"** 선택 +2. `n8n-cf-tunnel-workflow.json` 파일 업로드 +3. Credentials 연결: + - **cloudflare**: Cloudflare credential 선택 + - **npm**: NPM credential 선택 (있는 경우) + +### 2. Webhook API 워크플로우 임포트 +1. `n8n-webhook-workflow.json` 파일 임포트 +2. **Execute CF Agent** 노드에서: + - `CF-TUNNEL-AI-AGENT-WORKFLOW-ID`를 실제 워크플로우 ID로 변경 + +## 📡 API 사용법 + +### HTTP POST 요청 +```bash +curl -X POST "http://localhost:5678/webhook/cf-tunnel" \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "example.com", + "subdomain": "app", + "service_ip": "192.168.1.100", + "service_port": "8080" + }' +``` + +### 성공 응답 (200) +```json +{ + "success": true, + "domain": "app.example.com", + "tunnel_id": "0adb287c-10e2-4f1d-af4c-8e083ed878d4", + "tunnel_domain": "0adb287c-10e2-4f1d-af4c-8e083ed878d4.cfargotunnel.com", + "service": "192.168.1.100:8080", + "dns_configured": true, + "npm_configured": true, + "npm_host_id": "123", + "timestamp": "2024-09-07T01:00:00.000Z", + "message": "🚀 AI Agent 완료: app.example.com → 192.168.1.100:8080" +} +``` + +### 에러 응답 (400/500) +```json +{ + "error": true, + "message": "Missing required fields: domain, subdomain", + "required_fields": ["domain", "subdomain", "service_ip", "service_port"], + "example": { + "domain": "example.com", + "subdomain": "app", + "service_ip": "192.168.1.100", + "service_port": "8080" + } +} +``` + +## 🔧 커스터마이징 + +### 1. 터널 ID 변경 +각 워크플로우의 **Initialize Config** 노드에서: +```javascript +tunnel_id: 'YOUR-TUNNEL-ID-HERE', +tunnel_domain: 'YOUR-TUNNEL-ID-HERE.cfargotunnel.com', +``` + +### 2. 계정 ID 변경 +```javascript +account_id: 'YOUR-ACCOUNT-ID-HERE' +``` + +### 3. NPM 설정 수정 +**Create NPM Proxy** 노드에서 SSL, 캐싱 등 설정 변경 가능: +```json +{ + "ssl_forced": true, + "caching_enabled": true, + "certificate_id": 1, + "meta": { + "letsencrypt_agree": true, + "dns_challenge": true + } +} +``` + +## 🔒 보안 고려사항 + +### 1. API 키 보호 +- Vault 연동 사용 권장 +- n8n Credentials에 직접 저장 시 암호화 확인 +- 최소 권한 원칙 적용 + +### 2. 웹훅 보안 +```javascript +// Webhook 노드에 인증 추가 +const authHeader = $input.all()[0].headers.authorization; +if (!authHeader || authHeader !== 'Bearer YOUR-SECRET-TOKEN') { + return [{ json: { error: true, message: 'Unauthorized' } }]; +} +``` + +### 3. Rate Limiting +n8n에서 실행 제한 설정: +- **Execution Timeout**: 300초 +- **Max Executions**: 시간당 제한 설정 + +## 📊 모니터링 및 로깅 + +### 1. 실행 로그 확인 +n8n 대시보드 → **Executions** → 워크플로우 실행 기록 확인 + +### 2. 에러 알림 설정 +Error Workflow 생성하여 실패 시 알림 발송: +```json +{ + "name": "CF-Tunnel-Error-Handler", + "nodes": [ + { + "name": "Send Slack Alert", + "type": "n8n-nodes-base.slack" + } + ] +} +``` + +### 3. 성능 메트릭 +- 평균 실행 시간: ~30-60초 +- 성공률: >95% 목표 +- API 응답 시간 모니터링 + +## 🧪 테스트 시나리오 + +### 1. 기본 테스트 +```bash +# 새 도메인 생성 +curl -X POST "http://localhost:5678/webhook/cf-tunnel" \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "test.com", + "subdomain": "api", + "service_ip": "127.0.0.1", + "service_port": "3000" + }' +``` + +### 2. 기존 도메인 업데이트 +```bash +# 같은 subdomain.domain으로 다른 서비스로 업데이트 +curl -X POST "http://localhost:5678/webhook/cf-tunnel" \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "test.com", + "subdomain": "api", + "service_ip": "127.0.0.1", + "service_port": "4000" + }' +``` + +### 3. 에러 테스트 +```bash +# 잘못된 IP 주소 +curl -X POST "http://localhost:5678/webhook/cf-tunnel" \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "test.com", + "subdomain": "api", + "service_ip": "999.999.999.999", + "service_port": "3000" + }' +``` + +## 🚀 프로덕션 배포 + +### 1. Docker Compose 설정 +```yaml +version: '3.8' +services: + n8n: + image: n8nio/n8n + ports: + - "5678:5678" + environment: + - N8N_HOST=0.0.0.0 + - N8N_PORT=5678 + - N8N_PROTOCOL=https + - N8N_BASIC_AUTH_ACTIVE=true + - N8N_BASIC_AUTH_USER=admin + - N8N_BASIC_AUTH_PASSWORD=secure-password + volumes: + - n8n_data:/home/node/.n8n + restart: unless-stopped + +volumes: + n8n_data: +``` + +### 2. 리버스 프록시 설정 +```nginx +server { + listen 80; + server_name n8n.yourdomain.com; + + location / { + proxy_pass http://localhost:5678; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` + +## 📝 추가 기능 아이디어 + +1. **Bulk API**: 여러 도메인 한번에 설정 +2. **Status Check**: 터널 상태 모니터링 API +3. **SSL Certificate**: Let's Encrypt 자동 설정 +4. **Health Check**: 서비스 상태 확인 및 알림 +5. **Rollback**: 설정 되돌리기 기능 + +--- + +이제 n8n에서 Cloudflare 터널을 자동화하는 AI 에이전트가 준비되었습니다! 🤖✨ \ No newline at end of file