init: SR System — Helpdesk & ITAM Portal
This commit is contained in:
@@ -0,0 +1,643 @@
|
||||
# 배포 가이드 (Deployment Guide)
|
||||
|
||||
## 1. 전체 아키텍처
|
||||
|
||||
### 시스템 구성도
|
||||
|
||||
```
|
||||
[User Browser]
|
||||
│
|
||||
├── https://sr.example.com ──────────────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
Cloudflare DNS ─── Cloudflare Pages ──── Cloudflare Tunnel
|
||||
(도메인 관리) (Next.js 정적 호스팅) (outbound 전용)
|
||||
│
|
||||
│ http://localhost:8080
|
||||
▼
|
||||
TrueNAS Scale
|
||||
├── Docker: Spring Boot (:8080)
|
||||
├── Docker: PostgreSQL (:5432)
|
||||
└── Dataset: 첨부파일 저장소
|
||||
```
|
||||
|
||||
### 데이터 흐름
|
||||
|
||||
```
|
||||
1. User → https://sr.example.com → Cloudflare Pages (Next.js SPA)
|
||||
2. SPA → GET https://api.sr.example.com/v1/tickets
|
||||
│
|
||||
3. Cloudflare DNS → Cloudflare Tunnel (443) → cloudflared 컨테이너
|
||||
4. cloudflared → http://spring-boot:8080/api/v1/tickets
|
||||
5. Spring Boot → PostgreSQL (:5432) / Dataset (/data/attachments)
|
||||
```
|
||||
|
||||
### 포트 오픈 현황
|
||||
|
||||
| 방향 | 프로토콜 | 포트 | 설명 |
|
||||
|------|---------|------|------|
|
||||
| **아웃바운드** | TCP | 443 | cloudflared → Cloudflare Edge |
|
||||
| 인바운드 | **없음** | - | 포트포워딩 불필요 |
|
||||
|
||||
TrueNAS에 **열린 인바운드 포트가 0개**. cloudflared가 아웃바운드 연결만 생성하여 Cloudflare와 통신.
|
||||
|
||||
---
|
||||
|
||||
## 2. 사전 준비
|
||||
|
||||
### 2.1 Cloudflare
|
||||
|
||||
- Cloudflare 계정 (https://dash.cloudflare.com)
|
||||
- 도메인 Cloudflare DNS 위임 완료
|
||||
- Cloudflare Pages 가입 (무료 티어 가능)
|
||||
|
||||
### 2.2 TrueNAS Scale
|
||||
|
||||
- TrueNAS Scale 24.04+ (Linux 기반)
|
||||
- Apps 기능 활성화: **Apps → Settings → Choose Pool** (앱 전용 Dataset 선택)
|
||||
- Docker 네트워크 확인: `docker network ls`
|
||||
|
||||
### 2.3 GitHub
|
||||
|
||||
- Frontend Repository (`sr-frontend`)
|
||||
- Backend Repository (`sr-backend`)
|
||||
- GitHub Secrets 등록 준비
|
||||
|
||||
---
|
||||
|
||||
## 3. 1단계: Backend Docker화
|
||||
|
||||
### 3.1 Dockerfile
|
||||
|
||||
Spring Boot 프로젝트 루트에 `Dockerfile` 생성:
|
||||
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM gradle:8.7-jdk17 AS builder
|
||||
WORKDIR /app
|
||||
COPY build.gradle settings.gradle ./
|
||||
COPY src ./src
|
||||
RUN gradle build -x test --no-daemon
|
||||
|
||||
# Runtime stage
|
||||
FROM eclipse-temurin:17-jre
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/build/libs/*.jar app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
```
|
||||
|
||||
### 3.2 application-prod.yml
|
||||
|
||||
`src/main/resources/application-prod.yml` 생성:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:postgresql://postgres:5432/sr_system
|
||||
username: ${DB_USERNAME}
|
||||
password: ${DB_PASSWORD}
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: validate
|
||||
show-sql: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 50MB
|
||||
max-request-size: 100MB
|
||||
|
||||
app:
|
||||
file:
|
||||
upload-dir: /data/attachments
|
||||
jwt:
|
||||
secret: ${JWT_SECRET}
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.hq.support.portal: INFO
|
||||
```
|
||||
|
||||
### 3.3 docker-compose.yml
|
||||
|
||||
최상위 `docker/infra/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
container_name: sr-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: sr_system
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/apps/sr-system/postgres:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d sr_system"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
spring-boot:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: sr-backend
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: prod
|
||||
DB_USERNAME: ${DB_USERNAME}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
volumes:
|
||||
- /mnt/apps/sr-system/attachments:/data/attachments
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
```
|
||||
|
||||
> **중요:** `ports`가 `127.0.0.1:8080:8080`으로 설정됨. 외부 직접 접근 불가, cloudflared를 통해서만 접근 가능.
|
||||
|
||||
---
|
||||
|
||||
## 4. 2단계: TrueNAS Scale 배포
|
||||
|
||||
### 4.1 Dataset 생성
|
||||
|
||||
TrueNAS GUI → Storage → Create Dataset:
|
||||
|
||||
| 항목 | 경로 | 용도 |
|
||||
|------|------|------|
|
||||
| App Config | `/mnt/apps/sr-system` | docker-compose, 환경변수 |
|
||||
| PostgreSQL Data | `/mnt/apps/sr-system/postgres` | DB 데이터 |
|
||||
| Attachments | `/mnt/apps/sr-system/attachments` | 첨부파일 저장소 |
|
||||
|
||||
### 4.2 환경변수 파일
|
||||
|
||||
`/mnt/apps/sr-system/.env` 생성:
|
||||
|
||||
```bash
|
||||
DB_USERNAME=sr_admin
|
||||
DB_PASSWORD=<복잡한_비밀번호>
|
||||
JWT_SECRET=<openssl rand -base64 64>
|
||||
```
|
||||
|
||||
### 4.3 Custom App 등록
|
||||
|
||||
TrueNAS GUI → Apps → Launch Docker Image 대신 **Custom App** 사용:
|
||||
|
||||
1. **App Name:** `sr-system`
|
||||
2. **Image:** (docker-compose 방식 사용)
|
||||
3. **Add Container → docker-compose:**
|
||||
|
||||
TrueNAS Apps → Discover Apps → Custom App 선택 후 아래 내용 입력:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
container_name: sr-postgres
|
||||
restart: unless-stopped
|
||||
env_file: /mnt/apps/sr-system/.env
|
||||
volumes:
|
||||
- /mnt/apps/sr-system/postgres:/var/lib/postgresql/data
|
||||
networks:
|
||||
- sr-network
|
||||
|
||||
spring-boot:
|
||||
image: sr-backend:latest
|
||||
container_name: sr-backend
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
env_file: /mnt/apps/sr-system/.env
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: prod
|
||||
volumes:
|
||||
- /mnt/apps/sr-system/attachments:/data/attachments
|
||||
networks:
|
||||
- sr-network
|
||||
|
||||
networks:
|
||||
sr-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
> **참고:** docker-compose 방식 대신 TrueNAS Apps GUI의 **Custom App → Container Images**에서 각 이미지를 개별 등록하고 `Network`를 동일한 bridge 네트워크로 연결해도 됨.
|
||||
|
||||
### 4.4 수동 빌드 (초기)
|
||||
|
||||
백엔드 코드를 TrueNAS에 복사 후 빌드:
|
||||
|
||||
```bash
|
||||
# TrueNAS SSH 접속
|
||||
cd /mnt/apps/sr-system
|
||||
git clone https://github.com/your-org/sr-backend.git
|
||||
cd sr-backend
|
||||
docker build -t sr-backend:latest .
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 3단계: Cloudflare Tunnel 설치
|
||||
|
||||
### 5.1 Cloudflare Tunnel 생성 (로컬 CLI)
|
||||
|
||||
```bash
|
||||
# 로컬 PC에서 cloudflared 설치
|
||||
brew install cloudflare/cloudflare/cloudflared
|
||||
|
||||
# Cloudflare 로그인
|
||||
cloudflared tunnel login
|
||||
|
||||
# Tunnel 생성
|
||||
cloudflared tunnel create sr-system-tunnel
|
||||
|
||||
# 출력 예시: Tunnel ID: abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
# 인증 파일: ~/.cloudflared/abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
|
||||
```
|
||||
|
||||
### 5.2 Config 파일 생성
|
||||
|
||||
`~/.cloudflared/config.yml`:
|
||||
|
||||
```yaml
|
||||
tunnel: abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
credentials-file: /home/.cloudflared/abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
|
||||
|
||||
ingress:
|
||||
- hostname: api.sr.example.com
|
||||
service: http://localhost:8080
|
||||
- service: http_status:404
|
||||
```
|
||||
|
||||
### 5.3 DNS 라우팅 설정
|
||||
|
||||
```bash
|
||||
cloudflared tunnel route dns sr-system-tunnel api.sr.example.com
|
||||
```
|
||||
|
||||
### 5.4 TrueNAS에 cloudflared 컨테이너 배포
|
||||
|
||||
**방법 A: Docker Compose에 포함**
|
||||
|
||||
`docker/infra/docker-compose.yml`에 cloudflared 추가:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# ... postgres, spring-boot ...
|
||||
|
||||
cloudflared:
|
||||
image: cloudflare/cloudflared:latest
|
||||
container_name: sr-tunnel
|
||||
restart: unless-stopped
|
||||
command: tunnel --no-autoupdate run
|
||||
environment:
|
||||
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
|
||||
networks:
|
||||
- sr-network
|
||||
```
|
||||
|
||||
**방법 B: TrueNAS Apps에서 개별 배포**
|
||||
|
||||
1. TrueNAS → Apps → Discover Apps → Custom App
|
||||
2. **App Name:** `sr-tunnel`
|
||||
3. **Image:** `cloudflare/cloudflared:latest`
|
||||
4. **Entrypoint:** `tunnel --no-autoupdate run`
|
||||
5. **Environment Variables:**
|
||||
- `TUNNEL_TOKEN`: `<Tunnel Token>`
|
||||
|
||||
### 5.5 Tunnel Token 발급
|
||||
|
||||
```bash
|
||||
cloudflared tunnel token sr-system-tunnel > tunnel-token.txt
|
||||
# 출력된 token을 CLOUDFLARE_TUNNEL_TOKEN 환경변수로 등록
|
||||
```
|
||||
|
||||
### 5.6 동작 확인
|
||||
|
||||
```bash
|
||||
# Tunnel 로그 확인
|
||||
docker logs sr-tunnel
|
||||
|
||||
# 정상 출력 예시:
|
||||
# 2026/05/21 10:00:00 INF Connection abc12345 registered
|
||||
# 2026/05/21 10:00:00 INF Route created hostname=api.sr.example.com
|
||||
# 2026/05/21 10:00:00 INF tunnelId=abc12345
|
||||
|
||||
# Spring Boot 헬스체크
|
||||
curl https://api.sr.example.com/api/v1/actuator/health
|
||||
# {"status":"UP"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 4단계: Frontend Cloudflare Pages 배포
|
||||
|
||||
### 6.1 next.config.ts 설정
|
||||
|
||||
```typescript
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "export", // 정적 사이트 내보내기
|
||||
images: {
|
||||
unoptimized: true, // 정적 export 시 필수
|
||||
},
|
||||
trailingSlash: true,
|
||||
distDir: "out",
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
```
|
||||
|
||||
> **참고:** API Routes나 Server Components가 필요하면 `output: 'export'` 대신 `@cloudflare/next-on-pages` 사용.
|
||||
|
||||
### 6.2 환경변수
|
||||
|
||||
`.env.production`:
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_API_URL=https://api.sr.example.com/api/v1
|
||||
```
|
||||
|
||||
### 6.3 Cloudflare Pages 연결
|
||||
|
||||
1. Cloudflare Dashboard → **Workers & Pages → Pages**
|
||||
2. **Connect to Git** → GitHub 저장소 선택
|
||||
3. **Build settings:**
|
||||
- Framework preset: **Next.js**
|
||||
- Build command: `npm run build && npm run export`
|
||||
- Build output: `out`
|
||||
4. **Environment Variables (Advanced):**
|
||||
- `NEXT_PUBLIC_API_URL`: `https://api.sr.example.com/api/v1`
|
||||
5. **Deploy**
|
||||
|
||||
### 6.4 Custom Domain 설정
|
||||
|
||||
Deploy 완료 후:
|
||||
1. Pages 프로젝트 → **Custom domains** → **Set up custom domain**
|
||||
2. `sr.example.com` 입력
|
||||
3. Cloudflare가 자동으로 DNS 레코드 생성 (Proxy ON = 주황 구름)
|
||||
|
||||
---
|
||||
|
||||
## 7. 5단계: CI/CD
|
||||
|
||||
### 7.1 Backend (GitHub Actions)
|
||||
|
||||
`.github/workflows/deploy-backend.yml`:
|
||||
|
||||
```yaml
|
||||
name: Deploy Backend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "backend/**"
|
||||
- "docker/**"
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
cd backend
|
||||
./gradlew build -x test
|
||||
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
cd backend
|
||||
docker build -t ghcr.io/${{ github.repository }}/sr-backend:latest .
|
||||
docker tag ghcr.io/${{ github.repository }}/sr-backend:latest \
|
||||
ghcr.io/${{ github.repository }}/sr-backend:${{ github.sha }}
|
||||
|
||||
- name: Push to GitHub Container Registry
|
||||
run: |
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
docker push ghcr.io/${{ github.repository }}/sr-backend --all-tags
|
||||
|
||||
- name: Deploy to TrueNAS
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.TRUENAS_HOST }}
|
||||
username: ${{ secrets.TRUENAS_SSH_USER }}
|
||||
key: ${{ secrets.TRUENAS_SSH_KEY }}
|
||||
script: |
|
||||
cd /mnt/apps/sr-system
|
||||
docker compose pull spring-boot
|
||||
docker compose up -d spring-boot
|
||||
docker image prune -f
|
||||
```
|
||||
|
||||
### 7.2 Frontend (GitHub Actions)
|
||||
|
||||
`.github/workflows/deploy-frontend.yml`:
|
||||
|
||||
```yaml
|
||||
name: Deploy Frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "frontend/**"
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install & Build
|
||||
run: |
|
||||
cd frontend
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
uses: cloudflare/pages-action@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: sr-frontend
|
||||
directory: frontend/out
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
```
|
||||
|
||||
### 7.3 GitHub Secrets 등록
|
||||
|
||||
| Secret | 값 |
|
||||
|--------|-----|
|
||||
| `TRUENAS_HOST` | TrueNAS IP 주소 (내부망) |
|
||||
| `TRUENAS_SSH_USER` | SSH 사용자 |
|
||||
| `TRUENAS_SSH_KEY` | SSH Private Key |
|
||||
| `CLOUDFLARE_API_TOKEN` | Cloudflare API Token (Pages 권한) |
|
||||
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare Account ID |
|
||||
| `TUNNEL_TOKEN` | Cloudflare Tunnel Token |
|
||||
|
||||
---
|
||||
|
||||
## 8. 보안 설정
|
||||
|
||||
### 8.1 Cloudflare WAF 규칙
|
||||
|
||||
Cloudflare Dashboard → Security → WAF:
|
||||
|
||||
**규칙 1: API 경로만 허용**
|
||||
```
|
||||
Field: Hostname
|
||||
Operator: equals
|
||||
Value: api.sr.example.com
|
||||
|
||||
Then:
|
||||
URI Path starts with /api/v1 OR /actuator/health
|
||||
→ Allow
|
||||
Else → Block
|
||||
```
|
||||
|
||||
**규칙 2: Rate Limiting**
|
||||
```
|
||||
When: requests match api.sr.example.com
|
||||
Rate: 1000 requests per 5 minutes
|
||||
Action: Block
|
||||
```
|
||||
|
||||
### 8.2 Cloudflare Access (선택 - VPN 대체)
|
||||
|
||||
Zero Trust → Access → Applications:
|
||||
|
||||
- **App Domain:** `api.sr.example.com`
|
||||
- **Policy:** 특정 이메일/Google/OAuth 로그인 필수
|
||||
- **Session Duration:** 24h
|
||||
|
||||
> Cloudflare Access를 활성화하면 API도 인증된 사용자만 접근 가능. 단, 프론트엔드 SPA에서 API 호출 시 Access Token 처리 로직이 추가로 필요.
|
||||
|
||||
### 8.3 SSL 설정
|
||||
|
||||
Cloudflare Dashboard → SSL/TLS:
|
||||
- **Full (Strict)** 선택
|
||||
- TrueNAS 측에서는 별도 SSL 인증서 불필요 (cloudflared가 종단 암호화)
|
||||
|
||||
### 8.4 DB 접근 제한
|
||||
|
||||
PostgreSQL이 `127.0.0.1:5432`에서만 리스닝. 외부 접근 차단.
|
||||
Docker 네트워크 내에서만 `postgres:5432`로 접근 가능.
|
||||
|
||||
---
|
||||
|
||||
## 9. 운영
|
||||
|
||||
### 9.1 헬스체크
|
||||
|
||||
```bash
|
||||
# Spring Boot Actuator
|
||||
curl https://api.sr.example.com/api/v1/actuator/health
|
||||
|
||||
# DB 연결 확인
|
||||
curl https://api.sr.example.com/api/v1/actuator/health/db
|
||||
```
|
||||
|
||||
### 9.2 로그 확인
|
||||
|
||||
```bash
|
||||
# TrueNAS SSH 접속 후
|
||||
docker logs sr-backend # Spring Boot 로그
|
||||
docker logs sr-postgres # PostgreSQL 로그
|
||||
docker logs sr-tunnel # Tunnel 로그
|
||||
docker compose logs -f # 실시간 로그 스트림
|
||||
```
|
||||
|
||||
### 9.3 DB 백업
|
||||
|
||||
**ZFS Snapshot (자동):**
|
||||
TrueNAS GUI → Storage → `/mnt/apps/sr-system/postgres` → Snapshot:
|
||||
- Schedule: Daily at 03:00
|
||||
- Retention: 30일
|
||||
|
||||
**pg_dump (수동):**
|
||||
```bash
|
||||
docker exec sr-postgres pg_dump -U sr_admin sr_system > \
|
||||
/mnt/apps/sr-system/backups/sr_system_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
### 9.4 Watchtower (자동 업데이트)
|
||||
|
||||
docker-compose에 Watchtower 추가:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: sr-watchtower
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --interval 3600 --cleanup
|
||||
```
|
||||
|
||||
매시간 이미지 체크 → 새 이미지 있으면 자동 재배포.
|
||||
|
||||
---
|
||||
|
||||
## 10. 문제 해결
|
||||
|
||||
### Tunnel 연결 안 됨
|
||||
|
||||
```bash
|
||||
# cloudflared 로그 확인
|
||||
docker logs sr-tunnel
|
||||
|
||||
# DNS 확인
|
||||
cloudflared tunnel info sr-system-tunnel
|
||||
|
||||
# 재시작
|
||||
docker restart sr-tunnel
|
||||
```
|
||||
|
||||
### Spring Boot 컨테이너 Crash
|
||||
|
||||
```bash
|
||||
# 로그 확인
|
||||
docker logs sr-backend --tail 50
|
||||
|
||||
# DB 연결 테스트
|
||||
docker exec sr-postgres pg_isready -U sr_admin -d sr_system
|
||||
|
||||
# 환경변수 확인
|
||||
docker exec sr-backend env | grep -E "DB_|JWT_|SPRING_"
|
||||
```
|
||||
|
||||
### Cloudflare Pages 502 Error
|
||||
|
||||
- Cloudflare Tunnel이 실행 중인지 확인
|
||||
- `api.sr.example.com` DNS가 Tunnel UUID를 가리키는지 확인
|
||||
- Spring Boot가 정상 기동했는지 확인 (`http://localhost:8080/actuator/health`)
|
||||
- Cloudflare Dashboard → SSL/TLS → **Full (Strict)** 확인
|
||||
Reference in New Issue
Block a user