홈서버 구축 (미니PC)

개인 서버 구축(9) - nginx 설정하고 SSL 인증서로 HTTPS 받기 [마지막]

남건욱 2025. 7. 12. 19:38
반응형

1. Nginx 설치

sudo apt update
sudo apt install -y nginx
sudo systemctl status nginx

- sudo apt update로 패키지 목록을 업데이트해준다.

- sudo apt install -y nginx로 Nginx를 설치해 준다.

- sudo systemctl status nginx로 서비스 상태를 조회한다.

 

초록색으로 활성화가 떴다고 조회되면 올바르게 설치된 것이다.

 

sudo rm /etc/nginx/sites-enabled/default

기본으로 들어있는 /etc/nginx/sites-enabled/default 파일을 지워준다.

default 설정을 지우는 이유는 어차피 사용하지 않을 것이고, 기본값이 내가 따로 설정할 값과 충돌할 수 있기 때문에 지워줬다.

 

upstream react_app {
    server 127.0.0.1:3000;
}
upstream springboot {
    server 127.0.0.1:8080;
}

# ─────────────────────────────────
# 1) HTTP 전용: 80번 포트에서 HTTPS로만 리다이렉트
# ─────────────────────────────────
server {
    listen      80;
    server_name tripmark.co.kr www.tripmark.co.kr;

    # HTTP로 들어오는 모든 요청을 HTTPS로
    return 301 https://$host$request_uri;
}

# ─────────────────────────────────
# 2) HTTPS 전용: 443번 포트에서 React/API 프록시
# ─────────────────────────────────
server {
    listen              443 ssl http2;
    server_name         tripmark.co.kr www.tripmark.co.kr;

    # SSL 인증서 경로 (certbot이 발급해 준 경로)
    ssl_certificate     /etc/letsencrypt/live/tripmark.co.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tripmark.co.kr/privkey.pem;

    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    # 공통 프록시 헤더
    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 요청은 스프링부트 컨테이너로
    location ^~ /api/ {
        proxy_pass http://springboot;
        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;
        
        # SSE 를 위한 버퍼링 해제
        proxy_buffering     off;
        proxy_cache         off;
        add_header          Cache-Control    "no-cache";
        proxy_http_version  1.1;
    }

    # ──────────────────────────────────────────
    # WebSocket (SockJS) 엔드포인트 프록시
    # ──────────────────────────────────────────
    location /ws-chat {
        proxy_pass          http://springboot/ws-chat;
        proxy_http_version  1.1;
        proxy_set_header    Upgrade           $http_upgrade;
        proxy_set_header    Connection        "Upgrade";
        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;
        # optionally disable buffering for WS
        proxy_buffering     off;
    }

    location /service/images/ {
        alias           {이미지 경로};
        access_log      off;
        expires         30d;
        add_header      Cache-Control "public";
        # 정적 파일(디렉터리) 조회
        try_files       $uri $uri/ =404;
    }

    # 그 외는 React 컨테이너로
    location / {
        proxy_pass http://react_app;
    }
}

/etc/nginx/sites-available/ 경로에서 스프링부트+리액트를 합친 .conf 파일 생성을 해준다.

나는 서버+화면을 한 번에 nginx 설정에 넣었다.

 

sudo ln -s /etc/nginx/sites-available/footprint.conf  /etc/nginx/sites-enabled/

설정 파일을 sites-enabled로 심볼릭 링크해 nginx 설정을 활성화해 준다.

 

sudo nginx -t
sudo systemctl reload nginx

nginx -t로 오류 유무를 파악해 준 뒤 systemctl reload nginx로 방금 만든 설정을 불러와준다.

 

 

2. docker-compose.yml 설정

version: "3.9"

services:
  # ────────────────────────────────────────────────────────────
  # Spring Boot Backend
  # ────────────────────────────────────────────────────────────
  backend:
    image: footprint-backend:latest
    container_name: footprint-backend
    restart: always
    ports:
      - "8080:8080"
    environment:
      # Spring Boot 프로퍼티 오버라이드
      SPRING_PROFILES_ACTIVE: prod
      SPRING_DATASOURCE_URL: jdbc:mariadb://mariadb:{db포트}/footprint
      SPRING_DATASOURCE_USERNAME: {db아이디}
      SPRING_DATASOURCE_PASSWORD: {db비밀번호}
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: "{redis포트}"
      SPRING_DATA_MONGODB_URI: mongodb://mongodb:{mongodb포트}/{db명}
      MAIL_USERNAME: {smtp아이디}
      MAIL_PASSWORD: {smtp비밀번호}
    depends_on:
      - mariadb
      - redis
      - mongodb
    volumes:
      - /home/gunwook/app/service/images:/home/gunwook/app/service/images

  # ────────────────────────────────────────────────────────────
  # React + Nginx Frontend
  # ────────────────────────────────────────────────────────────
  frontend:
    image: footprint-frontend:latest
    container_name: footprint-frontend
    restart: always
    ports:
      - "3000:80"
    depends_on:
      - backend

  # ────────────────────────────────────────────────────────────
  # MariaDB
  # ────────────────────────────────────────────────────────────
  mariadb:
    image: mariadb:10.6
    container_name: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: {db아이디}
      MYSQL_DATABASE: {db비밀번호}
    ports:
      - "{db포트}:{db포트}"
    volumes:
      - mariadb_data:/var/lib/mysql

이제 jenkins를 설정하기 전에 docker-compose.yml 파일을 만들어준다.

 

 

3. Jenkins 설정 (서버, 화면)

이제 젠킨스에서 서버 Pipeline 설정부터 해준다. 

 

pipeline {
  agent any

  // GitHub Webhook 쓰려면 triggers { githubPush() } 또는 위 체크박스만으로 충분
  triggers {
    githubPush()
  }

  environment {
    // 도커 이미지 이름
    IMAGE_NAME = "footprint-backend"
    // docker-compose.yml 위치
    SERVICE_DIR = "/home/gunwook/app/service"
  }

  stages {
    stage('Checkout') {
      steps {
        // private repo 접근용 credentialsId 는 'tripmark'
        git credentialsId: 'tripmark',
            url: 'https://github.com/gunwooknam2023/footprint.git',
            branch: 'main'
      }
    }
    
    stage('Grant Exec Permission') {
      steps {
        sh 'chmod +x gradlew'
      }
    }

    stage('Build JAR') {
      steps {
        // 테스트 제외하고 빠르게 빌드
        sh './gradlew clean bootJar -x test'
      }
    }

    stage('Build Docker Image') {
      steps {
        // 컨테이너용 이미지 빌드
        sh "docker build -t ${IMAGE_NAME}:latest ."
      }
    }

    stage('Deploy via Docker Compose') {
      steps {
        sh '''
          cd /home/gunwook/app/service
          docker compose pull || true
          docker compose up -d
        '''
      }
    }
  }

  post {
    success {
      echo "✅ Deployment successful: ${IMAGE_NAME}:latest"
    }
    failure {
      echo "❌ Deployment failed!"
    }
  }
}

 

 

 

그다음 화면 Pipeline를 설정해준다. 

 

pipeline {
  agent any

  triggers {
    githubPush()
  }

  environment {
    IMAGE_NAME  = "footprint-frontend"
    SERVICE_DIR = "/home/gunwook/app/service"
  }

  stages {
    stage('Checkout') {
      steps {
        git credentialsId: 'tripmark',
            url: 'https://github.com/gunwooknam2023/footprintfront.git',
            branch: 'main'
      }
    }

    stage('Build Docker Image') {
      steps {
        // Dockerfile 및 default.conf가 워크스페이스에 있으므로 바로 빌드
        sh "docker build -t ${IMAGE_NAME}:latest ."
      }
    }

    stage('Deploy via Docker Compose') {
      steps {
        sh """
          cd ${SERVICE_DIR}
          docker compose pull || true
          docker compose up -d
        """
      }
    }
  }

  post {
    success {
      echo "✅ Frontend deployed: ${IMAGE_NAME}:latest"
    }
    failure {
      echo "❌ Frontend deployment failed."
    }
  }
}

 

 

 

 

4. SSL을 사용한 인증서 생성 + https 적용

sudo apt update
sudo apt install -y certbot python3-certbot-nginx

sudo apt update로 패키지 목록을 최신 상태로 갱신해 준다.

sudo apt install -y certbot python3-certbot-nginx로 certbot이 nginx 설정을 자동으로 찾아서 SSL 인증서를 설치, 갱신해 주도록 한다. -y옵션으로 설치 중 묻는 옵션에 yes로 자동응답 하도록 설정했다.

 

sudo certbot --nginx \     # nginx 플러그인을 사용해 인증서 발급 후 nginx 설정을 자동으로 수정
  -d tripmark.co.kr \      # 인증서를 적용할 도메인을 지정
  -d www.tripmark.co.kr \  #                           ""
  --agree-tos \            # 서비스 약관에 자동 동의
  --redirect \             # HTTP 요청을 HTTPS로 자동 리다이렉트하도록 nginx 설정 추가
  --no-eff-email \         # 뉴스레터 수신 동의 및 이메일 공유를 건너뜀
  -m ngwdevelop@gmail.com  # 인증서 만료 알림 등을 받을 관리자 이메일 지정

그 뒤 SSL 인증서를 발급하고 리다이렉트 설정까지 해주도록 했다.

 

Congratulations! You have successfully enabled HTTPS on https://tripmark.co.kr and https://www.tripmark.co.kr

위처럼 떴다면 이제 도메인에 HTTPS가 활성화 됐을 것이다.

 

잘 적용된 모습이다. 

 

 

이로써 홈서버 구축부터 파이프라인 및 Jenkins 연동, 도메인 설정, SSL 기반 HTTPS 구성까지 모두 완료하여 기본 환경 구성을 마무리했다.

반응형