diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 43eea57..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..dbf7477
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,8 @@
+.git
+.gradle
+build/
+out/
+bin/
+Dockerfile
+.dockerignore
+README.md
\ No newline at end of file
diff --git a/.gemini/settings.json b/.gemini/settings.json
new file mode 100644
index 0000000..c1420d0
--- /dev/null
+++ b/.gemini/settings.json
@@ -0,0 +1,5 @@
+{
+ "ui": {
+ "theme": "ANSI Light"
+ }
+}
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md
index fa7d32f..51cf244 100644
--- a/.github/ISSUE_TEMPLATE/feature.md
+++ b/.github/ISSUE_TEMPLATE/feature.md
@@ -13,4 +13,4 @@ assignees: ""
### 💡 기타 참고 사항
-
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 8938d7d..d419620 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,13 +1,19 @@
-### 📌 관련 이슈
+## 📌 관련 이슈
+
+
-### ✨ 작업 내용 요약
+## ✨ 작업 내용 요약
+
+
-### 🛠️ 주요 변경 사항
+## 🛠️ 주요 변경 사항
+
+
-### 📚 체크리스트
+## 📚 체크리스트
- [ ] 팀 컨벤션에 맞는 커밋 메시지를 작성했나요?
- [ ] 로컬 환경에서 정상 작동하는지 확인했나요?
- [ ] 불필요한 주석이나 print문은 제거했나요?
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..64ebc7d
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,96 @@
+name: Pace Project CI/CD # 워크플로우 이름 설정
+
+on:
+ push:
+ branches: [ "main", "develop" ] # 해당 브랜치에 코드가 push될 때만 실행
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest # 깃허브가 제공하는 최신 우분투 가상 환경에서 작업
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4 # 깃허브 서버로 내 소스 코드를 가져옴
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: 'gradle'
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ - name: Run Tests with Gradle
+ run: ./gradlew test
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3 # 도커 허브 접속 시도
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }} # 깃허브 시크릿에서 아이디 가져옴
+ password: ${{ secrets.DOCKERHUB_TOKEN }} # 깃허브 시크릿에서 토큰 가져옴
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v5 # 도커 이미지 빌드 및 전송
+ with:
+ context: . # 현재 위치의 파일을 바탕으로 빌드
+ push: true # 빌드 성공 시 도커 허브로 즉시 보냄
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/pace-project:latest # 이미지 이름과 태그 붙임
+
+ - name: Prepare directory on EC2
+ uses: appleboy/ssh-action@v1.0.3
+ with:
+ host: ${{ secrets.EC2_HOST }}
+ username: ${{ secrets.EC2_USERNAME }}
+ key: ${{ secrets.EC2_SSH_KEY }}
+ script: mkdir -p ~/pace-project/nginx
+
+ - name: Copy docker-compose.yml via scp
+ uses: appleboy/scp-action@v0.1.7
+ with:
+ host: ${{ secrets.EC2_HOST }}
+ username: ${{ secrets.EC2_USERNAME }}
+ key: ${{ secrets.EC2_SSH_KEY }}
+ source: "docker-compose.yml,nginx/default.conf" # 내 깃허브에 있는 파일 이름
+ target: "~/pace-project" # 서버에 저장될 폴더 이름
+
+ - name: Deploy to EC2
+ uses: appleboy/ssh-action@v1.0.3 # SSH를 통해 AWS EC2 서버에 접속
+ with:
+ host: ${{ secrets.EC2_HOST }} # EC2의 IP 주소로 연결
+ username: ${{ secrets.EC2_USERNAME }} # 접속 계정(보통 ubuntu) 사용
+ key: ${{ secrets.EC2_SSH_KEY }} # .pem 키 내용으로 인증
+ script: | # 접속 후 실행할 명령어들 시작
+ mkdir -p ~/pace-project # 프로젝트 폴더가 없으면 생성
+ cd ~/pace-project # 해당 폴더로 이동
+
+ docker pull ${{ secrets.DOCKERHUB_USERNAME }}/pace-project:latest # 창고에서 새 이미지 가져옴
+
+ # 서버에서 사용할 비밀 장부(.env)를 시크릿 값으로 새로 만듦
+ echo "MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }}" > .env
+ echo "MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}" >> .env
+ echo "MYSQL_USER=${{ secrets.MYSQL_USER }}" >> .env
+ echo "MYSQL_PASSWORD=${{ secrets.MYSQL_PASSWORD }}" >> .env
+ echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" >> .env
+ echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
+ echo "KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }}" >> .env
+ echo "KAKAO_REDIRECT_URI=${{ secrets.KAKAO_REDIRECT_URI }}" >> .env
+ echo "GOOGLE_MAPS_API_KEY=${{ secrets.GOOGLE_MAPS_API_KEY }}" >> .env
+ echo "SEOUL_SUBWAY_API_KEY=${{ secrets.SEOUL_SUBWAY_API_KEY }}" >> .env
+ docker-compose up -d --remove-orphans # 새 이미지로 세트 메뉴(DB+앱) 다시 실행
+ docker image prune -f
+
+ # 헬스 체크: 서버가 제대로 떴는지 10번 확인함
+ echo "Starting health check..."
+ for i in {1..10}; do
+ RESPONSE=$(curl -s -H "Host: pace-server.kro.kr" http://localhost/health) # 내 서버에 안부를 물어봄
+ if [ "$RESPONSE" = "OK" ]; then # 대답이 "OK"면 성공
+ echo "Health check passed!"
+ exit 0
+ fi
+ echo "Waiting for server... ($i/10)" # 아직 안 떴으면 10초 기다림
+ sleep 10
+ done
+ echo "Health check failed." # 10번 다 실패하면 배포 실패 처리
+ exit 1
diff --git a/.gitignore b/.gitignore
index c2065bc..80d6f37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
+.gemini
### STS ###
.apt_generated
@@ -35,3 +36,6 @@ out/
### VS Code ###
.vscode/
+
+.DS_Store
+.env
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..d6cae52
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,33 @@
+# 빌드 스테이지(eclipse-temurin을 사용하여 jar 파일 생성)
+FROM eclipse-temurin:21-jdk-jammy AS build
+
+# 컨테이너 내부의 작업 디렉토리를 /app으로 설정
+WORKDIR /workspace
+
+# 의존성 캐시 단계
+COPY gradlew .
+COPY gradle gradle
+COPY settings.gradle build.gradle ./
+
+# Gradle 래퍼(/gradlew)에 실행 권한 부여 및 라이브러리 다운로드
+RUN chmod +x ./gradlew && ./gradlew --no-daemon dependencies
+
+# 빌드 단계
+COPY src src
+RUN ./gradlew --no-daemon clean bootJar -x test
+
+# 실행 단계
+FROM eclipse-temurin:21-jre-jammy AS runtime
+WORKDIR /app
+
+# 보안을 위한 비관리자 유저 생성
+RUN useradd -ms /bin/bash appuser
+USER appuser
+
+# 빌드 결과물만 복사
+COPY --from=build /workspace/build/libs/*.jar app.jar
+
+EXPOSE 8080
+
+# 한국 시간 설정 및 실행
+ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-jar", "app.jar"]
diff --git a/README.md b/README.md
index 050ab24..7589e72 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,70 @@
-# Pace_server
-UMC 9기 'Pace' 서비스 server 팀
+# Pace Server 🏃♂️
+
+> **UMC 9기 'Pace' 서버팀**
+
+## 📖 프로젝트 개요
+
+**Pace**는 사용자의 일정과 이동 경로를 효율적으로 관리할 수 있도록 돕는 모바일 애플리케이션입니다. **카카오 로그인**을 통한 간편한 인증을 지원하며, 대중교통 데이터를 활용한 일정 관리, 경로 추천, 장소 저장 등의 기능을 제공합니다.
+
+## 🛠 백엔드 기술 스택 (Tech Stack)
+
+### 환경 (Environment)
+* 
+* 
+* 
+
+### 데이터베이스 & ORM
+* 
+* **Spring Data JPA**
+* **QueryDSL 5.0**
+
+### 보안 & 인증 (Security & Auth)
+* **Spring Security**
+* **OAuth 2.0 (Kakao Login)**
+* **JWT (JSON Web Token)**
+
+### API & 문서화
+* **SpringDoc OpenAPI (Swagger UI)**
+* **WebFlux (WebClient)** - 외부 API 연동
+
+### 유틸리티 (Utilities)
+* **Apache POI** - 엑셀 데이터 처리 (버스/지하철 정보)
+* **Lombok**
+
+## 📂 프로젝트 구조
+
+```bash
+src/main/java/com/example/pace
+├── PaceApplication.java
+├── domain
+│ ├── auth # 인증 (Kakao, JWT)
+│ ├── member # 회원 관리, 장소 보관함, 설정
+│ ├── schedule # 일정 및 경로 관리
+│ ├── terms # 약관 관리
+│ └── transit # 대중교통 데이터 로직
+└── global
+ ├── apiPayload # 표준 API 응답 구조
+ ├── auth # 시큐리티 설정, Custom User Details
+ ├── config # 앱 설정 (Swagger, WebClient 등)
+ └── entity # Base Entities
+```
+
+## ✨ 주요 기능
+
+### 1. 인증 (Authentication)
+* **카카오 로그인**: Kakao OAuth2를 이용한 간편 로그인.
+* **토큰 관리**: Access/Refresh Token 발급 및 재발급(Reissue).
+* **계정 관리**: 로그아웃 및 회원 탈퇴 기능.
+
+### 2. 일정 관리 (Schedule Management)
+* **생성/삭제**: 개인 일정 등록 및 삭제.
+* **조회**: 일별, 월별 일정 목록 조회.
+* **경로**: 대중교통 정보를 활용한 일정 경로 관리.
+
+### 3. 회원 및 설정 (Member & Settings)
+* **프로필**: 사용자 정보 관리.
+* **장소 보관함**: 자주 가는 장소 즐겨찾기 및 그룹 관리.
+* **온보딩**: 초기 사용자 설정 프로세스.
+
+### 4. 대중교통 통합 (Transit Integration)
+* **데이터 로딩**: 버스 및 지하철 데이터(Excel/JSON)를 로드하여 경로 계산에 활용.
diff --git a/build.gradle b/build.gradle
index 1895f35..8502b1d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,8 @@
plugins {
- id 'java'
- id 'org.springframework.boot' version '4.0.1'
- id 'io.spring.dependency-management' version '1.1.7'
+ id 'java'
+ id 'org.springframework.boot' version '4.0.1'
+ id 'io.spring.dependency-management' version '1.1.7'
+ id 'org.jetbrains.kotlin.jvm'
}
group = 'com.example'
@@ -9,38 +10,88 @@ version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'
java {
- toolchain {
- languageVersion = JavaLanguageVersion.of(21)
- }
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
}
configurations {
- compileOnly {
- extendsFrom annotationProcessor
- }
+ compileOnly {
+ extendsFrom annotationProcessor
+ }
}
repositories {
- mavenCentral()
+ mavenCentral()
}
dependencies {
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- implementation 'org.springframework.boot:spring-boot-starter-security'
- implementation 'org.springframework.boot:spring-boot-starter-security-oauth2-client'
- implementation 'org.springframework.boot:spring-boot-starter-webmvc'
- compileOnly 'org.projectlombok:lombok'
- developmentOnly 'org.springframework.boot:spring-boot-devtools'
- runtimeOnly 'com.mysql:mysql-connector-j'
- annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
- annotationProcessor 'org.projectlombok:lombok'
- testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
- testImplementation 'org.springframework.boot:spring-boot-starter-security-oauth2-client-test'
- testImplementation 'org.springframework.boot:spring-boot-starter-security-test'
- testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
- testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+ implementation 'org.springframework.boot:spring-boot-starter-security'
+ implementation 'org.springframework.boot:spring-boot-starter-security-oauth2-client'
+
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ compileOnly 'org.projectlombok:lombok'
+ developmentOnly 'org.springframework.boot:spring-boot-devtools'
+ runtimeOnly 'com.mysql:mysql-connector-j'
+ annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
+ annotationProcessor 'org.projectlombok:lombok'
+
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
+ testImplementation 'org.springframework.boot:spring-boot-starter-security-oauth2-client-test'
+ testImplementation 'org.springframework.boot:spring-boot-starter-security-test'
+ testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+ testRuntimeOnly 'com.h2database:h2'
+
+ // Swagger UI
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1")
+
+ // jwt
+ implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
+ implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
+ implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
+ implementation 'org.springframework.boot:spring-boot-configuration-processor'
+
+ // WebClient
+ implementation 'org.springframework.boot:spring-boot-starter-webflux'
+
+ // Excel (Apache POI)
+ implementation 'org.apache.poi:poi-ooxml:5.4.0'
+
+ // QueryDSL : OpenFeign
+ implementation "io.github.openfeign.querydsl:querydsl-jpa:7.0"
+ implementation "io.github.openfeign.querydsl:querydsl-core:7.0"
+ annotationProcessor "io.github.openfeign.querydsl:querydsl-apt:7.0:jpa"
+ annotationProcessor "jakarta.persistence:jakarta.persistence-api"
+ annotationProcessor "jakarta.annotation:jakarta.annotation-api"
+
+ // idk
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
+
+ // redis
+ implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
+
tasks.named('test') {
- useJUnitPlatform()
+ useJUnitPlatform()
+}
+
+def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
+
+// 소스 세트에 생성 경로 추가
+sourceSets {
+ main.java.srcDirs += [querydslDir]
+}
+
+// 컴파일 시 생성 경로 지정
+tasks.withType(JavaCompile).configureEach {
+ options.generatedSourceOutputDirectory.set(querydslDir)
}
+
+// clean 태스크에 생성 폴더 삭제 로직
+clean.doLast {
+ file(querydslDir).deleteDir()
+}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..f119d60
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,100 @@
+services:
+ # Nginx
+ pace-nginx:
+ image: nginx:stable-alpine
+ container_name: pace-nginx
+ restart: always
+ depends_on:
+ - pace-app
+ networks:
+ - pace-network
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
+ - ./certbot/conf:/etc/letsencrypt
+ - ./certbot/www:/var/www/certbot
+
+ # Certbot 서비스(ssl 인증서 발급)
+ certbot:
+ image: certbot/certbot
+ container_name: certbot
+ volumes:
+ - ./certbot/conf:/etc/letsencrypt
+ - ./certbot/www:/var/www/certbot
+
+ # 데이터베이스 서비스
+ pace-redis:
+ image: redis:alpine
+ command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
+ container_name: pace-redis
+ restart: always
+ ports:
+ - "127.0.0.1:6379:6379"
+ volumes:
+ - redis_data:/data
+ networks:
+ - pace-network
+
+ pace-mysql:
+ image: mysql:8.0
+ container_name: pace-mysql
+ restart: always
+ environment:
+ # .env 파일에서 변수를 읽어와 보안을 유지
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_DATABASE: ${MYSQL_DATABASE}
+ MYSQL_USER: ${MYSQL_USER}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+
+ TZ: Asia/Seoul
+ # 한글 및 이모지 지원을 위한 설정
+ command: >
+ --character-set-server=utf8mb4
+ --collation-server=utf8mb4_unicode_ci
+ ports:
+ - "127.0.0.1:3306:3306"
+ # 컨테이너가 삭제되어도 데이터가 보존되도록 볼륨을 설정
+ volumes:
+ - mysql_data:/var/lib/mysql
+ networks:
+ - pace-network
+
+ # Spring Boot
+ pace-app:
+ # Docker Hub의 Dockerfile을 기반으로 이미지를 빌드
+ image: shootingstar1020/pace-project:latest
+ container_name: pace-app
+ restart: always
+ # DB 컨테이너가 먼저 실행된 후 애플리케이션이 실행되도록 순서를 보장
+ depends_on:
+ - pace-mysql
+ - pace-redis
+ environment:
+ # DB 접속 주소에 서비스 이름(pace-db)을 사용하여 내부 통신을 수행
+ SPRING_DATASOURCE_URL: jdbc:mysql://pace-mysql:3306/${MYSQL_DATABASE}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
+ SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
+ SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
+ REDIS_HOST: pace-redis
+ REDIS_PORT: 6379
+ REDIS_PASSWORD: ${REDIS_PASSWORD}
+ SPRING_PROFILES_ACTIVE: prod
+ JWT_SECRET: ${JWT_SECRET}
+ KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID}
+ KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI}
+ GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY}
+ SEOUL_SUBWAY_API_KEY: ${SEOUL_SUBWAY_API_KEY}
+
+ networks:
+ - pace-network
+
+# 서비스들이 서로 소통할 수 있는 가상 네트워크 정의
+networks:
+ pace-network:
+ driver: bridge
+
+# 데이터 보존을 위한 명명된 볼륨 정의
+volumes:
+ mysql_data:
+ redis_data:
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f8e1ee3..1b33c55 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradlew b/gradlew
index adff685..23d15a9 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015 the original authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -114,6 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
+CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -171,6 +172,7 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -210,6 +212,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
diff --git a/gradlew.bat b/gradlew.bat
index c4bdd3a..db3a6ac 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -70,10 +70,11 @@ goto fail
:execute
@rem Setup the command line
+set CLASSPATH=
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/nginx/default.conf b/nginx/default.conf
new file mode 100644
index 0000000..b8f4fdf
--- /dev/null
+++ b/nginx/default.conf
@@ -0,0 +1,78 @@
+server {
+ listen 80;
+ server_name pace-server.kro.kr;
+
+ location /.well-known/acme-challenge/ {
+ root /var/www/certbot;
+ }
+
+ location = /health {
+ proxy_pass http://pace-app:8080/health;
+ access_log off;
+ }
+
+ location / {
+ # host: 사용자가 접속한 도메인
+ # request_uri: 도메인 뒤의 주소
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl;
+
+ # 인증서 파일 경로(Certbot이 만들어준 파일들)
+ ssl_certificate /etc/letsencrypt/live/pace-server.kro.kr/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/pace-server.kro.kr/privkey.pem;
+
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+
+ server_name pace-server.kro.kr;
+ # 내 사이트를 다른 사이트의