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 <noreply@anthropic.com>
This commit is contained in:
14
README.md
14
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
|
||||
|
||||
195
anvil-ses-final-setup.md
Normal file
195
anvil-ses-final-setup.md
Normal file
@@ -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: '<h1>Welcome!</h1>',
|
||||
headers: {
|
||||
'List-Unsubscribe': '<mailto:unsubscribe@anvil.it.com>, <https://anvil.it.com/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'] = '<mailto:unsubscribe@anvil.it.com>, <https://anvil.it.com/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을 신뢰할 수 있는 발신자로 인식한다는 의미입니다.
|
||||
271
aws-ses-setup.md
Normal file
271
aws-ses-setup.md
Normal file
@@ -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': '<h1>Hello</h1>', '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 = """
|
||||
<html>
|
||||
<body>
|
||||
<h1>안녕하세요!</h1>
|
||||
<p>AWS SES로 발송된 <strong>HTML 메일</strong>입니다.</p>
|
||||
</body>
|
||||
</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/)
|
||||
69
cloudflare-vault-integration.md
Normal file
69
cloudflare-vault-integration.md
Normal file
@@ -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 사용
|
||||
552
gitea-setup.md
Normal file
552
gitea-setup.md
Normal file
@@ -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 <repository-url> 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.
|
||||
273
n8n-setup-guide.md
Normal file
273
n8n-setup-guide.md
Normal file
@@ -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 에이전트가 준비되었습니다! 🤖✨
|
||||
Reference in New Issue
Block a user