feat: Ubuntu 서버용 심플 nginx 배포 시스템 구축
- GitHub Actions를 심플하게 재구성 (불필요한 테스트 로그 제거) - SSL 자동 설정 (Let's Encrypt) - 프록시 라우팅 업데이트: /api/ → 18000, /rb8001/ → 8001 - 배포 경로: /opt/robeing-nginx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
cf666af1ee
commit
c09ba6a017
110
.github/workflows/deploy.yml
vendored
110
.github/workflows/deploy.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Deploy to NAS (rsync)
|
name: Deploy to Ubuntu Server
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@ -8,107 +8,29 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup SSH key
|
- name: Setup SSH key
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
with:
|
with:
|
||||||
ssh-private-key: ${{ secrets.NAS_SSH_KEY_ADMIN }}
|
ssh-private-key: ${{ secrets.NAS_SSH_KEY_ADMIN }}
|
||||||
|
|
||||||
- name: Check SSH key loaded
|
- name: Deploy via SSH
|
||||||
run: ssh-add -l
|
env:
|
||||||
|
HOST: ${{ secrets.NAS_HOST }}
|
||||||
- name: Add NAS host to known_hosts
|
PORT: ${{ secrets.NAS_PORT }}
|
||||||
|
USER: ${{ secrets.NAS_USER }}
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
ssh -o StrictHostKeyChecking=no -p $PORT $USER@$HOST << 'EOF'
|
||||||
ssh-keyscan -p ${{ secrets.NAS_PORT }} ${{ secrets.NAS_HOST }} >> ~/.ssh/known_hosts
|
sudo mkdir -p /opt/robeing-nginx
|
||||||
|
|
||||||
- name: Test SSH connection
|
|
||||||
run: |
|
|
||||||
ssh -o StrictHostKeyChecking=no -p ${{ secrets.NAS_PORT }} \
|
|
||||||
${{ secrets.NAS_USER }}@${{ secrets.NAS_HOST }} echo "SSH connection successful"
|
|
||||||
|
|
||||||
- name: Test directory access
|
|
||||||
run: |
|
|
||||||
ssh -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} \
|
|
||||||
"ls -la /volume1/homes/admin/ && whoami && pwd"
|
|
||||||
|
|
||||||
- name: Create target directory if not exists
|
|
||||||
run: |
|
|
||||||
ssh -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} \
|
|
||||||
"mkdir -p /volume1/homes/admin/nginx-infra && ls -la /volume1/homes/admin/nginx-infra"
|
|
||||||
|
|
||||||
- name: Test rsync availability
|
|
||||||
run: |
|
|
||||||
ssh -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} \
|
|
||||||
"which rsync && rsync --version"
|
|
||||||
|
|
||||||
- name: Deploy with file ownership fix
|
|
||||||
run: |
|
|
||||||
tar czf - --exclude='.git' . | ssh -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} \
|
|
||||||
"mkdir -p /tmp/nginx-infra-deploy && cd /tmp/nginx-infra-deploy && tar xzf - && cp -rf /tmp/nginx-infra-deploy/* /volume1/homes/admin/nginx-infra/ 2>/dev/null || true && rm -rf /tmp/nginx-infra-deploy"
|
|
||||||
|
|
||||||
- name: Check Docker permissions
|
|
||||||
run: |
|
|
||||||
ssh -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} \
|
|
||||||
"ls -la /var/run/docker.sock && id"
|
|
||||||
|
|
||||||
- name: Create deployment archive
|
|
||||||
run: |
|
|
||||||
mkdir -p /tmp/deploy-build
|
|
||||||
tar czf /tmp/deploy-build/deploy.tar.gz --exclude='.git' --exclude='*.tar.gz' --warning=no-file-changed .
|
|
||||||
|
|
||||||
- name: Copy archive to NAS
|
|
||||||
run: scp -O -o ConnectTimeout=10 -o ServerAliveInterval=60 -P ${{ secrets.NAS_PORT }} /tmp/deploy-build/deploy.tar.gz admin@${{ secrets.NAS_HOST }}:/tmp/
|
|
||||||
|
|
||||||
- name: Deploy with atomic swap
|
|
||||||
run: |
|
|
||||||
ssh -o ConnectTimeout=10 -o ServerAliveInterval=60 -p ${{ secrets.NAS_PORT }} admin@${{ secrets.NAS_HOST }} << 'EOF'
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
DEPLOY=/volume1/homes/admin/nginx-infra
|
|
||||||
TMPDIR=$(mktemp -d /tmp/deploy.XXXX)
|
|
||||||
BACKUP=${DEPLOY}-backup-$(date +%Y%m%d%H%M%S)
|
|
||||||
|
|
||||||
# 1) tar로 임시 디렉터리에 풀기
|
|
||||||
cd "$TMPDIR" && tar xzf /tmp/deploy.tar.gz
|
|
||||||
|
|
||||||
# 2) 기존 배포물을 백업
|
|
||||||
if [ -d "$DEPLOY" ]; then
|
|
||||||
mv "$DEPLOY" "$BACKUP"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3) 임시 → 실제 위치로 교체
|
|
||||||
mv "$TMPDIR" "$DEPLOY"
|
|
||||||
|
|
||||||
# 4) 오래된 백업 5개만 남기기
|
|
||||||
ls -1dt ${DEPLOY}-backup-* 2>/dev/null | tail -n +6 | xargs -r rm -rf
|
|
||||||
|
|
||||||
echo "Deployed to $DEPLOY; backup saved at $BACKUP"
|
|
||||||
|
|
||||||
# 5) 포트 80 사용 중인 서비스 확인 및 처리
|
|
||||||
echo "Checking port 80 usage..."
|
|
||||||
netstat -tlnp | grep :80 || true
|
|
||||||
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep ":80" || true
|
|
||||||
|
|
||||||
# NAS 시스템 서비스가 80포트 사용 중이면 nginx를 8080으로 실행
|
if [ -d "/opt/robeing-nginx/.git" ]; then
|
||||||
if netstat -tln | grep -q ":80.*LISTEN"; then
|
cd /opt/robeing-nginx && git pull origin main
|
||||||
echo "Port 80 is used by system service, switching nginx to port 8080"
|
else
|
||||||
sed -i 's/80:80/8080:80/g' "$DEPLOY/docker-compose.yml"
|
git clone https://github.com/ivada-Robeing/nginx-deploy.git /opt/robeing-nginx
|
||||||
|
cd /opt/robeing-nginx
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Docker 컨테이너만 정리 (시스템 서비스는 건드리지 않음)
|
sudo mkdir -p ssl certbot-webroot
|
||||||
docker ps --filter "publish=80" -q | xargs -r docker stop
|
sudo docker-compose down || true
|
||||||
docker ps -a --filter "publish=80" -q | xargs -r docker rm
|
sudo docker-compose up -d
|
||||||
|
|
||||||
# 6) docker-compose 재시작
|
|
||||||
cd "$DEPLOY"
|
|
||||||
docker-compose down 2>/dev/null || true
|
|
||||||
docker-compose up -d --build
|
|
||||||
|
|
||||||
# 6) 임시 파일 정리
|
|
||||||
rm -f /tmp/deploy.tar.gz
|
|
||||||
EOF
|
EOF
|
||||||
13
README.md
13
README.md
@ -53,11 +53,14 @@ docker-compose -f docker-compose.yml up -d
|
|||||||
## 서비스 구성
|
## 서비스 구성
|
||||||
|
|
||||||
- **nginx**: 리버스 프록시 (포트 80, 443)
|
- **nginx**: 리버스 프록시 (포트 80, 443)
|
||||||
- **api-base**: API 서버 (포트 8000)
|
- **frontend/backend**: 통합 서버 (포트 18000)
|
||||||
- **test_api**: 테스트 API 서버 (포트 8001)
|
- **api_base**: API 서버 (포트 8001)
|
||||||
- **frontend**: 프론트엔드 서버 (포트 5173)
|
|
||||||
- **postgres**: PostgreSQL 데이터베이스
|
## 프록시 라우팅
|
||||||
- **redis**: Redis 캐시
|
|
||||||
|
- `https://ro-being.com/` → 192.168.219.45:5173 (메인 프론트엔드)
|
||||||
|
- `https://ro-being.com/api/` → 192.168.219.45:18000 (frontend/backend)
|
||||||
|
- `https://ro-being.com/rb8001/` → 192.168.219.45:8001 (api_base)
|
||||||
|
|
||||||
## Health Check
|
## Health Check
|
||||||
|
|
||||||
|
|||||||
53
default.conf
53
default.conf
@ -1,10 +1,53 @@
|
|||||||
|
# HTTP to HTTPS redirect
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
server_name ro-being.com;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://127.0.0.1:5137;
|
return 301 https://$server_name$request_uri;
|
||||||
proxy_set_header Host $host;
|
}
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
}
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
|
# HTTPS server
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name ro-being.com;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/live/ro-being.com/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/live/ro-being.com/privkey.pem;
|
||||||
|
|
||||||
|
# SSL settings
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
|
||||||
|
# Main application proxy
|
||||||
|
location / {
|
||||||
|
proxy_pass http://192.168.219.45:5173;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API endpoints
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://192.168.219.45:18000;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# RB8001 API endpoints
|
||||||
|
location /rb8001/ {
|
||||||
|
proxy_pass http://192.168.219.45:8001;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,6 +5,18 @@ services:
|
|||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
restart: always
|
- ./ssl:/etc/nginx/ssl:ro
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- certbot
|
||||||
|
|
||||||
|
certbot:
|
||||||
|
image: certbot/certbot:latest
|
||||||
|
volumes:
|
||||||
|
- ./ssl:/etc/letsencrypt
|
||||||
|
- ./certbot-webroot:/var/www/certbot
|
||||||
|
command: certonly --webroot --webroot-path=/var/www/certbot --email admin@ro-being.com --agree-tos --no-eff-email -d ro-being.com
|
||||||
|
restart: "no"
|
||||||
Loading…
x
Reference in New Issue
Block a user