From bd068328851fe30f97a47a57ae268ea3d14d3878 Mon Sep 17 00:00:00 2001 From: ywcheong Date: Tue, 31 Mar 2026 23:41:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=EC=97=94=EB=93=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20CORS=20?= =?UTF-8?q?=EC=A0=95=EC=B1=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sofia/config/security/CorsProperties.kt | 8 ++++++++ .../config/security/SecurityConfiguration.kt | 19 +++++++++++++++++++ src/main/resources/application.yaml | 3 +++ 3 files changed, 30 insertions(+) create mode 100644 src/main/kotlin/ywcheong/sofia/config/security/CorsProperties.kt diff --git a/src/main/kotlin/ywcheong/sofia/config/security/CorsProperties.kt b/src/main/kotlin/ywcheong/sofia/config/security/CorsProperties.kt new file mode 100644 index 0000000..23570b0 --- /dev/null +++ b/src/main/kotlin/ywcheong/sofia/config/security/CorsProperties.kt @@ -0,0 +1,8 @@ +package ywcheong.sofia.config.security + +import org.springframework.boot.context.properties.ConfigurationProperties + +@ConfigurationProperties(prefix = "sofia.cors") +data class CorsProperties( + val allowedOrigins: List, +) diff --git a/src/main/kotlin/ywcheong/sofia/config/security/SecurityConfiguration.kt b/src/main/kotlin/ywcheong/sofia/config/security/SecurityConfiguration.kt index fa38f03..12b33ff 100644 --- a/src/main/kotlin/ywcheong/sofia/config/security/SecurityConfiguration.kt +++ b/src/main/kotlin/ywcheong/sofia/config/security/SecurityConfiguration.kt @@ -1,5 +1,6 @@ package ywcheong.sofia.config.security +import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity @@ -8,19 +9,25 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.access.ExceptionTranslationFilter +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.CorsConfigurationSource +import org.springframework.web.cors.UrlBasedCorsConfigurationSource import ywcheong.sofia.config.mvc.GlobalExceptionHandler @Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) +@EnableConfigurationProperties(CorsProperties::class) class SecurityConfiguration( private val requestLoggingFilter: RequestLoggingFilter, private val apiKeyAuthFilter: ApiKeyAuthFilter, private val securityExceptionHandler: GlobalExceptionHandler.SecurityExceptionHandler, + private val corsProperties: CorsProperties, ) { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { return http + .cors { it.configurationSource(corsConfigurationSource()) } .csrf { it.disable() } .httpBasic { it.disable() } .formLogin { it.disable() } @@ -38,4 +45,16 @@ class SecurityConfiguration( ) .build() } + + private fun corsConfigurationSource(): CorsConfigurationSource { + val configuration = CorsConfiguration().apply { + allowedOrigins = corsProperties.allowedOrigins + allowedMethods = listOf("*") + allowedHeaders = listOf("*") + allowCredentials = true + } + return UrlBasedCorsConfigurationSource().apply { + registerCorsConfiguration("/**", configuration) + } + } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 99e67ab..59e24d6 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -36,3 +36,6 @@ sofia: from-name: KSA 국제부 번역버디 ERP dummy: enabled: false + cors: + allowed-origins: + - https://sofia.ywcheong.com From a2e4b7c16e9e9e79aee72fc7078aa562da760c27 Mon Sep 17 00:00:00 2001 From: ywcheong Date: Tue, 31 Mar 2026 23:47:09 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore:=20=EB=B0=B0=ED=8F=AC=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=9E=90=EC=B2=B4=EB=8F=84=20?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=EB=90=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 6cac0dc..487d048 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -41,11 +41,6 @@ jobs: - name: Build run: ./gradlew build - - name: Create and push tag - run: | - git tag "v${{ steps.version.outputs.version }}" - git push origin "v${{ steps.version.outputs.version }}" - - name: Setup SSH run: | mkdir -p ~/.ssh @@ -53,6 +48,12 @@ jobs: chmod 600 ~/.ssh/deploy_key ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null + - name: Upload deploy scripts to EC2 + run: | + scp -i ~/.ssh/deploy_key \ + deploy/deploy.sh deploy/init.sh \ + "${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}:${{ secrets.EC2_DEPLOY_DIR }}/" + - name: Upload jar to EC2 run: | scp -i ~/.ssh/deploy_key \ @@ -65,6 +66,11 @@ jobs: "${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}" \ "${{ secrets.EC2_DEPLOY_SCRIPT }} '${{ secrets.EC2_DEPLOY_DIR }}/sofia-${{ steps.version.outputs.version }}.jar'" + - name: Create and push tag + run: | + git tag "v${{ steps.version.outputs.version }}" + git push origin "v${{ steps.version.outputs.version }}" + - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: From 2681917351256511be786fb8f346e796faed7290 Mon Sep 17 00:00:00 2001 From: ywcheong Date: Wed, 1 Apr 2026 00:57:19 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20=EB=B0=B0=ED=8F=AC=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=B4=ED=94=84=EB=9D=BC=EC=9D=B8=20=EC=9E=AC=EA=B5=AC?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/deploy-to-ec2/action.yml | 65 +++++++++++++++ .github/actions/notify-failure/action.yml | 25 ++++++ .github/workflows/cd.yml | 79 ++++++++---------- .github/workflows/ci.yml | 20 ++--- .github/workflows/init.yml | 43 ++++++++++ deploy/deploy.sh | 98 +++++++++++++++++------ deploy/init.sh | 28 ++++++- deploy/nginx-sofia.conf | 23 ++++++ 8 files changed, 299 insertions(+), 82 deletions(-) create mode 100644 .github/actions/deploy-to-ec2/action.yml create mode 100644 .github/actions/notify-failure/action.yml create mode 100644 .github/workflows/init.yml create mode 100644 deploy/nginx-sofia.conf diff --git a/.github/actions/deploy-to-ec2/action.yml b/.github/actions/deploy-to-ec2/action.yml new file mode 100644 index 0000000..16def30 --- /dev/null +++ b/.github/actions/deploy-to-ec2/action.yml @@ -0,0 +1,65 @@ +name: Deploy to EC2 +description: Validate config, setup SSH, upload files, execute remote command + +inputs: + ssh-private-key: + required: true + description: SSH key for remote machine + host: + required: true + description: SSH host + username: + required: true + description: SSH username + files: + description: Space-separated list of local files to upload + required: false + remote-command: + description: Command to execute on the remote host + required: true + +runs: + using: composite + steps: + - name: 설정값 누락 확인 + shell: bash + env: + _SSH_PRIVATE_KEY: ${{ inputs.ssh-private-key }} + _HOST: ${{ inputs.host }} + _USERNAME: ${{ inputs.username }} + _REMOTE_COMMAND: ${{ inputs.remote-command }} + run: | + missing=() + for var in _SSH_PRIVATE_KEY _HOST _USERNAME _REMOTE_COMMAND; do + if [ -z "${!var}" ]; then + missing+=("${var#_}") + fi + done + if [ ${#missing[@]} -gt 0 ]; then + echo "::error::Missing: ${missing[*]}" + exit 1 + fi + echo "모든 필수 설정값이 확인되었습니다." + + - name: SSH 연결 준비 + shell: bash + run: | + mkdir -p ~/.ssh + echo "${{ inputs.ssh-private-key }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -H "${{ inputs.host }}" >> ~/.ssh/known_hosts 2>/dev/null + + - name: 파일 업로드 + if: ${{ inputs.files != '' }} + shell: bash + run: | + scp -i ~/.ssh/deploy_key \ + ${{ inputs.files }} \ + "${{ inputs.username }}@${{ inputs.host }}:/app/" + + - name: 원격 명령 실행 + shell: bash + run: | + ssh -i ~/.ssh/deploy_key \ + "${{ inputs.username }}@${{ inputs.host }}" \ + "${{ inputs.remote-command }}" diff --git a/.github/actions/notify-failure/action.yml b/.github/actions/notify-failure/action.yml new file mode 100644 index 0000000..5297453 --- /dev/null +++ b/.github/actions/notify-failure/action.yml @@ -0,0 +1,25 @@ +name: Notify Failure +description: Send failure notification via webhook + +inputs: + webhook-url: + description: Notification webhook URL (optional - skips if empty) + required: false + message: + description: Failure message to send + required: true + +runs: + using: composite + steps: + - name: 실패 알림 + shell: bash + env: + WEBHOOK_URL: ${{ inputs.webhook-url }} + MESSAGE: ${{ inputs.message }} + run: | + if [ -n "$WEBHOOK_URL" ]; then + curl -s -X POST "$WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d "{\"text\":\"${MESSAGE}\"}" + fi diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 487d048..2fbe5a0 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,4 +1,4 @@ -name: CD +name: Sofia CD Pipeline on: push: @@ -11,6 +11,11 @@ concurrency: permissions: contents: write +# 이 파이프라인이 필요로 하는 설정값 목록: +# Required Variables (비민감): EC2_HOST, EC2_USERNAME +# Required Secrets (민감): EC2_SSH_PRIVATE_KEY, SOFIA_DATASOURCE_URL, SOFIA_DATASOURCE_PASSWORD, SOFIA_DATASOURCE_USERNAME +# Optional Secrets (민감): NOTIFICATION_WEBHOOK_URL + jobs: deploy: runs-on: ubuntu-latest @@ -24,69 +29,53 @@ jobs: distribution: temurin java-version: "21" - - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ hashFiles('**/*.gradle.kts', 'gradle.properties') }} - restore-keys: gradle- + - uses: gradle/actions/setup-gradle@v4 - - name: Read version + - name: 버전 읽기 id: version run: | VERSION=$(grep 'ywcheong.sofia.version=' gradle.properties | cut -d'=' -f2) echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - - name: Build + - name: 빌드 run: ./gradlew build - - name: Setup SSH - run: | - mkdir -p ~/.ssh - echo "${{ secrets.EC2_SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key - chmod 600 ~/.ssh/deploy_key - ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null - - - name: Upload deploy scripts to EC2 - run: | - scp -i ~/.ssh/deploy_key \ - deploy/deploy.sh deploy/init.sh \ - "${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}:${{ secrets.EC2_DEPLOY_DIR }}/" - - - name: Upload jar to EC2 + - name: 시크릿 환경변수 파일 생성 + env: + SOFIA_DATASOURCE_URL: ${{ secrets.SOFIA_DATASOURCE_URL }} + SOFIA_DATASOURCE_PASSWORD: ${{ secrets.SOFIA_DATASOURCE_PASSWORD }} + SOFIA_DATASOURCE_USERNAME: ${{ secrets.SOFIA_DATASOURCE_USERNAME }} run: | - scp -i ~/.ssh/deploy_key \ - "build/libs/sofia-${{ steps.version.outputs.version }}.jar" \ - "${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}:${{ secrets.EC2_DEPLOY_DIR }}/" + { + echo "SOFIA_DATASOURCE_URL=${SOFIA_DATASOURCE_URL}" + echo "SOFIA_DATASOURCE_PASSWORD=${SOFIA_DATASOURCE_PASSWORD}" + echo "SOFIA_DATASOURCE_USERNAME=${SOFIA_DATASOURCE_USERNAME}" + } > deploy/secrets.env - - name: Run deploy script - run: | - ssh -i ~/.ssh/deploy_key \ - "${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}" \ - "${{ secrets.EC2_DEPLOY_SCRIPT }} '${{ secrets.EC2_DEPLOY_DIR }}/sofia-${{ steps.version.outputs.version }}.jar'" + - name: EC2 배포 + uses: ./.github/actions/deploy-to-ec2 + with: + ssh-private-key: ${{ secrets.EC2_SSH_PRIVATE_KEY }} + host: ${{ vars.EC2_HOST }} + username: ${{ vars.EC2_USERNAME }} + files: deploy/deploy.sh deploy/secrets.env build/libs/sofia-${{ steps.version.outputs.version }}.jar + remote-command: "/app/deploy.sh '/app/sofia-${{ steps.version.outputs.version }}.jar'" - - name: Create and push tag + - name: Git 태그 생성 및 푸시 run: | git tag "v${{ steps.version.outputs.version }}" git push origin "v${{ steps.version.outputs.version }}" - - name: Create GitHub Release + - name: GitHub Release 생성 uses: softprops/action-gh-release@v2 with: tag_name: "v${{ steps.version.outputs.version }}" files: build/libs/sofia-${{ steps.version.outputs.version }}.jar generate_release_notes: true - - name: Notify on failure + - name: 실패 알림 if: failure() - env: - WEBHOOK_URL: ${{ secrets.NOTIFICATION_WEBHOOK_URL }} - VERSION: ${{ steps.version.outputs.version }} - RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - run: | - if [ -n "$WEBHOOK_URL" ]; then - curl -s -X POST "$WEBHOOK_URL" \ - -H 'Content-Type: application/json' \ - -d "{\"text\":\"Sofia v${VERSION} 배포 실패\n${RUN_URL}\"}" - fi + uses: ./.github/actions/notify-failure + with: + webhook-url: ${{ secrets.NOTIFICATION_WEBHOOK_URL }} + message: "Sofia v${{ steps.version.outputs.version }} 배포 실패\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86fe615..11f4f9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI +name: Sofia CI Pipeline on: pull_request: @@ -15,13 +15,15 @@ jobs: distribution: temurin java-version: "21" - - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ hashFiles('**/*.gradle.kts', 'gradle.properties') }} - restore-keys: gradle- + - uses: gradle/actions/setup-gradle@v4 + + - name: 버전 태그 중복 확인 + run: | + VERSION=$(grep 'ywcheong.sofia.version=' gradle.properties | cut -d'=' -f2) + if git ls-remote --tags origin "refs/tags/v${VERSION}" | grep -q .; then + echo "::error::Tag v${VERSION} already exists. Update ywcheong.sofia.version in gradle.properties." + exit 1 + fi - - name: Run checks + - name: 검사 수행 run: ./gradlew check diff --git a/.github/workflows/init.yml b/.github/workflows/init.yml new file mode 100644 index 0000000..d5b8739 --- /dev/null +++ b/.github/workflows/init.yml @@ -0,0 +1,43 @@ +name: Sofia Remote Init (Run only once) + +on: + workflow_dispatch: + +concurrency: + group: init + cancel-in-progress: false + +# 이 파이프라인이 필요로 하는 설정값 목록: +# Required Variables (비민감): EC2_HOST, EC2_USERNAME +# Required Secrets (민감): EC2_SSH_PRIVATE_KEY +# Optional Secrets (민감): NOTIFICATION_WEBHOOK_URL + +jobs: + init: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: 인증서 파일 생성 + env: + CF_CERT: ${{ secrets.CLOUDFLARE_CERTS_CERT }} + CF_KEY: ${{ secrets.CLOUDFLARE_CERTS_KEY }} + run: | + printf '%s' "$CF_CERT" > deploy/cert.pem + printf '%s' "$CF_KEY" > deploy/key.pem + + - name: EC2 초기화 + uses: ./.github/actions/deploy-to-ec2 + with: + ssh-private-key: ${{ secrets.EC2_SSH_PRIVATE_KEY }} + host: ${{ vars.EC2_HOST }} + username: ${{ vars.EC2_USERNAME }} + files: deploy/init.sh deploy/nginx-sofia.conf deploy/cert.pem deploy/key.pem + remote-command: "bash /app/init.sh" + + - name: 실패 알림 + if: failure() + uses: ./.github/actions/notify-failure + with: + webhook-url: ${{ secrets.NOTIFICATION_WEBHOOK_URL }} + message: "Sofia 초기화 실패\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/deploy/deploy.sh b/deploy/deploy.sh index b63e682..acfa387 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -5,35 +5,83 @@ JAR_PATH="$1" PID_FILE="/app/sofia.pid" LOG_DIR="/app/log" -# 기존 프로세스 종료 -if [ -f "$PID_FILE" ]; then - OLD_PID=$(cat "$PID_FILE") - if kill -0 "$OLD_PID" 2>/dev/null; then - echo "Stopping existing process (PID: $OLD_PID)" - kill "$OLD_PID" - timeout 30 bash -c "while kill -0 $OLD_PID 2>/dev/null; do sleep 1; done" || true +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ENV_FILE="${SCRIPT_DIR}/secrets.env" + +stop_existing_process() { + if [ ! -f "$PID_FILE" ]; then + return + fi + + local old_pid + old_pid=$(cat "$PID_FILE") + + if kill -0 "$old_pid" 2>/dev/null; then + echo "Stopping existing process (PID: $old_pid)" + kill "$old_pid" + timeout 30 bash -c "while kill -0 $old_pid 2>/dev/null; do sleep 1; done" || true fi + rm -f "$PID_FILE" -fi +} -# 로그 디렉토리 생성 -mkdir -p "$LOG_DIR" +build_log_file() { + mkdir -p "$LOG_DIR" + local version + version=$(basename "$JAR_PATH" | sed 's/sofia-\(.*\)\.jar/\1/') + echo "${LOG_DIR}/$(date +%Y%m%d-%H%M%S)-${version}.log" +} -# 로그 파일명: {launch-date}-{version}.log -VERSION=$(basename "$JAR_PATH" | sed 's/sofia-\(.*\)\.jar/\1/') -LOG_FILE="${LOG_DIR}/$(date +%Y%m%d-%H%M%S)-${VERSION}.log" +refresh_secrets_from_env() { + local secret_keys=("SOFIA_DATASOURCE_URL" "SOFIA_DATASOURCE_PASSWORD" "SOFIA_DATASOURCE_USERNAME") + local available=false -# 환경변수 로드 후 실행 -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -ENV_FILE="${SCRIPT_DIR}/secrets.env" + for key in "${secret_keys[@]}"; do + if [ -n "${!key:-}" ]; then + available=true + break + fi + done + + if [ "$available" = true ]; then + echo "Refreshing secrets.env from environment variables" + > "$ENV_FILE" + for key in "${secret_keys[@]}"; do + if [ -n "${!key:-}" ]; then + echo "${key}=${!key}" >> "$ENV_FILE" + fi + done + fi +} + +load_env_file() { + if [ -f "$ENV_FILE" ]; then + set -a + source "$ENV_FILE" + set +a + fi +} + +start_application() { + local log_file="$1" + local version + version=$(basename "$JAR_PATH" | sed 's/sofia-\(.*\)\.jar/\1/') + + echo "Starting Sofia v${version}" + java \ + -Xms128m -Xmx256m \ + -XX:MetaspaceSize=64m \ + -XX:MaxMetaspaceSize=128m \ + -XX:+UseSerialGC \ + -jar "$JAR_PATH" > "$log_file" 2>&1 & -if [ -f "$ENV_FILE" ]; then - set -a - source "$ENV_FILE" - set +a -fi + echo $! > "$PID_FILE" + echo "Started (PID: $(cat "$PID_FILE"), Log: $log_file)" +} -echo "Starting Sofia v${VERSION}" -java -jar "$JAR_PATH" > "$LOG_FILE" 2>&1 & -echo $! > "$PID_FILE" -echo "Started (PID: $(cat "$PID_FILE"), Log: $LOG_FILE)" +# --- Main --- +stop_existing_process +log_file=$(build_log_file) +refresh_secrets_from_env +load_env_file +start_application "$log_file" diff --git a/deploy/init.sh b/deploy/init.sh index cb6ce56..c4f2b9f 100755 --- a/deploy/init.sh +++ b/deploy/init.sh @@ -1,8 +1,30 @@ #!/usr/bin/env bash set -euo pipefail -echo "Installing JDK 21 on Amazon Linux 2023..." -sudo dnf install -y java-21-amazon-corretto-devel +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -java -version +install_jdk() { + echo "Installing JDK 21 on Amazon Linux 2023..." + sudo dnf install -y java-21-amazon-corretto-devel + java -version +} + +install_and_configure_nginx() { + echo "Installing nginx..." + sudo dnf install -y nginx + + echo "Copying nginx config..." + sudo cp "${SCRIPT_DIR}/nginx-sofia.conf" /etc/nginx/conf.d/sofia.conf + sudo rm -f /etc/nginx/conf.d/welcome.conf /etc/nginx/sites-enabled/default 2>/dev/null || true + + echo "Validating nginx config..." + sudo nginx -t + + echo "Enabling and starting nginx..." + sudo systemctl enable --now nginx +} + +# --- Main --- +install_jdk +install_and_configure_nginx echo "Done." diff --git a/deploy/nginx-sofia.conf b/deploy/nginx-sofia.conf new file mode 100644 index 0000000..e0fb755 --- /dev/null +++ b/deploy/nginx-sofia.conf @@ -0,0 +1,23 @@ +server { + listen 80; + server_name _; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + server_name _; + + ssl_certificate /app/cert.pem; + ssl_certificate_key /app/key.pem; + + ssl_protocols TLSv1.2 TLSv1.3; + + location / { + proxy_pass http://127.0.0.1:8080; + 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; + } +} From 15d421bb31edb2b92cc7333bd545f3eac1a5de1c Mon Sep 17 00:00:00 2001 From: ywcheong Date: Wed, 1 Apr 2026 01:02:39 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore:=2026b.04.01.1=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a4e98c8..d064203 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ org.gradle.console=plain org.gradle.logging.level=quiet org.gradle.warning.mode=summary -ywcheong.sofia.version=26b.04.01 +ywcheong.sofia.version=26b.04.01.1 ywcheong.sofia.jdk_version=21 \ No newline at end of file