Spring Boot ์ฑ Nginx๋ก ๋ฐฐํฌํ๊ธฐ
๊ฐ์
Spring Boot ์ฑ์ ๋ด์ฅ ํฐ์บฃ์์ ์คํ๋๋ฉฐ, Nginx๋ ๋ฆฌ๋ฒ์ค ํ๋ก์๋ก์ ์๋จ์์ ์์ฒญ์ ๋ฐ์ Spring Boot์ ์ ๋ฌํ๋ค.
React๋ ์ ์ ํ์ผ์ ์ง์ ์๋นํ๋ฉด ๋์ง๋ง, Spring Boot๋ ๋ค๋ฆ
๋๋ค! Spring Boot๋ ์๊ธฐ ์์ ์ด ์น ์๋ฒ(๋ด์ฅ ํฐ์บฃ)๋ฅผ ๊ฐ์ง๊ณ ์์ด์ ์ค์ค๋ก HTTP ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์์ด์.
๊ทธ๋ฐ๋ฐ ์ Nginx๋ฅผ ์์ ๋๋๊ณ ์? Nginx๊ฐ ์์์ SSL ์ฒ๋ฆฌ, ๋ก๋ ๋ฐธ๋ฐ์ฑ, ์ ์ ํ์ผ ์บ์ฑ, ๋ณด์์ ๋ด๋นํด์ฃผ๋ฉด, Spring Boot๋ ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ ์ ์๊ฑฐ๋ ์. ๋ง์น ์๋น์์ ํ ์ง์(Nginx)์ด ์๋ ์๋๋ฅผ ํ๊ณ , ์ฃผ๋ฐฉ์ฅ(Spring Boot)์ ์๋ฆฌ์๋ง ์ง์คํ๋ ๊ฒ๊ณผ ๊ฐ์์!
๋ฐฐํฌ ์ํคํ
์ฒ
graph LR
A[๐ค ์ฌ์ฉ์<br/>๋ธ๋ผ์ฐ์ ] -->|"<https://api.example.com><br/>ํฌํธ 443"| B[๐ฅ๏ธ Nginx<br/>๋ฆฌ๋ฒ์ค ํ๋ก์]
B -->|"<http://localhost:8080><br/>๋ด๋ถ ํต์ "| C[๐ Spring Boot<br/>๋ด์ฅ ํฐ์บฃ]
C --> D[๐๏ธ Database<br/>MySQL/PostgreSQL]
style B fill:#90EE90
style C fill:#87CEEBMermaid
๋ณต์ฌ
flowchart TD
A["๐ป ๋ก์ปฌ ๊ฐ๋ฐ"] -->|"./gradlew build<br/>๋๋ mvn package"| B["๐ฆ JAR ํ์ผ ์์ฑ<br/>app.jar"]
B -->|"scp ๋๋ CI/CD"| C["๐ฅ๏ธ ์๋ฒ์ ์
๋ก๋"]
C --> D["๐ java -jar app.jar<br/>Spring Boot ์คํ"]
D --> E["โ๏ธ Nginx ๋ฆฌ๋ฒ์ค ํ๋ก์<br/>์ค์ + SSL"]
E --> F["๐ ์๋น์ค ์คํ!"]
style B fill:#FFD700
style E fill:#90EE90Mermaid
๋ณต์ฌ
Step 1: Spring Boot ์ฑ ๋น๋
# Gradle ํ๋ก์ ํธ
./gradlew clean build -x test
# ๊ฒฐ๊ณผ: build/libs/myapp-0.0.1-SNAPSHOT.jar
# Maven ํ๋ก์ ํธ
mvn clean package -DskipTests
# ๊ฒฐ๊ณผ: target/myapp-0.0.1-SNAPSHOT.jar
Bash
๋ณต์ฌ
Step 2: ์๋ฒ์ ์
๋ก๋ ๋ฐ ์คํ
# JAR ํ์ผ ์
๋ก๋
scp build/libs/myapp-0.0.1-SNAPSHOT.jar ubuntu@์๋ฒIP:/home/ubuntu/app/
# ์๋ฒ์์ ์คํ
cd /home/ubuntu/app
java -jar myapp-0.0.1-SNAPSHOT.jar
Bash
๋ณต์ฌ
Systemd ์๋น์ค๋ก ๋ฑ๋ก (๊ถ์ฅ!)
ํฐ๋ฏธ๋์์ ์ง์ java -jar๋ก ์คํํ๋ฉด, SSH ์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด ์ฑ๋ ๊ฐ์ด ์ฃฝ์ด์. ๊ทธ๋์ systemd ์๋น์ค๋ก ๋ฑ๋กํด์ผ ํด์!
sudo nano /etc/systemd/system/myapp.service
Bash
๋ณต์ฌ
[Unit]
Description=My Spring Boot Application
After=network.target
[Service]
User=ubuntu
ExecStart=/usr/bin/java -jar /home/ubuntu/app/myapp-0.0.1-SNAPSHOT.jar
SuccessExitStatus=143
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=SPRING_PROFILES_ACTIVE=prod
Environment=SERVER_PORT=8080
[Install]
WantedBy=multi-user.target
Plain Text
๋ณต์ฌ
# ์๋น์ค ๋ฑ๋ก ๋ฐ ์์
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp
# ์ํ ํ์ธ
sudo systemctl status myapp
# ๋ก๊ทธ ํ์ธ
sudo journalctl -u myapp -f
Bash
๋ณต์ฌ
ํญ๋ชฉ | ์ค๋ช
|
After=network.target | ๋คํธ์ํฌ๊ฐ ์ค๋น๋ ํ ์์ |
Restart=always | ์ฑ์ด ์ฃฝ์ผ๋ฉด ์๋ ์ฌ์์ |
RestartSec=5 | ์ฌ์์ ์ 5์ด ๋๊ธฐ |
Environment | ํ๊ฒฝ ๋ณ์ ์ค์ (ํ๋กํ์ผ, ํฌํธ ๋ฑ) |
Step 3: Nginx ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ค์
sudo nano /etc/nginx/sites-available/spring-app
Bash
๋ณต์ฌ
server {
listen 80;
server_name api.example.com;
# โญ ๋ฆฌ๋ฒ์ค ํ๋ก์ โ Spring Boot๋ก ์ ๋ฌ
location / {
proxy_pass <http://localhost: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;
# ํ์์์ ์ค์
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# WebSocket ์ง์ (ํ์์)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# ํฐ ํ์ผ ์
๋ก๋ ํ์ฉ
client_max_body_size 10M;
}
Plain Text
๋ณต์ฌ
ํ๋ก์ ํค๋๊ฐ ์ ํ์ํด?
sequenceDiagram
participant ์ฌ์ฉ์ as ๐ค ์ฌ์ฉ์<br/>IP: 203.0.113.50
participant Nginx as ๐ฅ๏ธ Nginx<br/>IP: 10.0.0.1
participant Spring as ๐ Spring Boot<br/>IP: 127.0.0.1
์ฌ์ฉ์->>Nginx: ์์ฒญ (IP: 203.0.113.50)
Note over Nginx: ํค๋ ์์ด ์ ๋ฌํ๋ฉด<br/>Spring์ Nginx IP๋ง ๋ณด์
Nginx->>Spring: ์์ฒญ ์ ๋ฌ
Note over Nginx,Spring: X-Real-IP: 203.0.113.50<br/>X-Forwarded-For: 203.0.113.50<br/>X-Forwarded-Proto: https
Note over Spring: ์ด์ ์ง์ง ์ฌ์ฉ์ IP๋ฅผ<br/>์ ์ ์์ด์!Mermaid
๋ณต์ฌ
ํค๋ | ์ญํ |
Host | ์๋ ์์ฒญ๋ ๋๋ฉ์ธ ์ด๋ฆ |
X-Real-IP | ์ค์ ํด๋ผ์ด์ธํธ IP |
X-Forwarded-For | ํ๋ก์ ์ฒด์ธ์ ๊ฑฐ์น IP ๋ชฉ๋ก |
X-Forwarded-Proto | ์๋ ํ๋กํ ์ฝ (http/https) |
์ด ํค๋๊ฐ ์์ผ๋ฉด Spring Boot๋ ๋ชจ๋ ์์ฒญ์ด 127.0.0.1(Nginx)์์ ์จ ๊ฒ์ผ๋ก ์ธ์ํด์. ์ฌ์ฉ์์ ์ง์ง IP๋ฅผ ์ ์ ์๊ฒ ๋๋ ๊ฑฐ์ฃ !
Step 4: ํ์ฑํ ๋ฐ SSL ์ ์ฉ
# ์ฌ์ดํธ ํ์ฑํ
sudo ln -s /etc/nginx/sites-available/spring-app /etc/nginx/sites-enabled/
# ํ
์คํธ ๋ฐ ์ ์ฉ
sudo nginx -t && sudo systemctl reload nginx
# SSL ์ ์ฉ
sudo certbot --nginx -d api.example.com
Bash
๋ณต์ฌ
์ต์ข
์ค์ (HTTPS ํฌํจ)
# ์
์คํธ๋ฆผ ์ ์ (๋ก๋ ๋ฐธ๋ฐ์ฑ ๋๋น)
upstream spring_backend {
server localhost:8080;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
# ๋ฆฌ๋ฒ์ค ํ๋ก์
location / {
proxy_pass http://spring_backend;
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;
}
# Health Check ์๋ํฌ์ธํธ (๋ก๊น
์ ์ธ)
location = /actuator/health {
proxy_pass http://spring_backend;
access_log off;
}
client_max_body_size 10M;
}
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
Plain Text
๋ณต์ฌ
Spring Boot application.yml ์ค์
server:
port: 8080
forward-headers-strategy: framework # โญ ํ๋ก์ ํค๋ ์ธ์ (ํ์!)
# Actuator (Health Check)
management:
endpoints:
web:
exposure:
include: health
YAML
๋ณต์ฌ
forward-headers-strategy: framework ์ค์ ์ ๊ผญ ํด์ฃผ์ธ์! ์ด๊ฑธ ์ ํ๋ฉด Spring Boot๊ฐ Nginx๊ฐ ๋ณด๋ด์ฃผ๋ X-Forwarded-* ํค๋๋ฅผ ๋ฌด์ํด์.
์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์
๋ฌธ์ | ์์ธ | ํด๊ฒฐ |
502 Bad Gateway | Spring Boot๊ฐ ์ ๋์๊ฐ๊ณ ์์ | systemctl status myapp์ผ๋ก ํ์ธ |
504 Gateway Timeout | ์๋ต ์๊ฐ ์ด๊ณผ | proxy_read_timeout ๋๋ฆฌ๊ธฐ |
CORS ์๋ฌ | ํ๋ก ํธ-๋ฐฑ ๋๋ฉ์ธ ๋ค๋ฆ | Spring Boot์ CORS ์ค์ or Nginx์์ ์ฒ๋ฆฌ |
๋ฆฌ๋ค์ด๋ ํธ ๋ฌดํ ๋ฃจํ | X-Forwarded-Proto ๋ฏธ์ค์ | ํ๋ก์ ํค๋ ์ค์ ํ์ธ |
ํ์ผ ์
๋ก๋ ์คํจ | ํฌ๊ธฐ ์ ํ | client_max_body_size ๋๋ฆฌ๊ธฐ |
์ค์ต
์ค์ต ํ๊ฒฝ
ํญ๋ชฉ | ๊ฐ |
๋ก์ปฌ ํ๋ก์ ํธ | Spring Boot + Gradle |
๋น๋ ๊ฒฐ๊ณผ๋ฌผ | build/libs/APP.war |
์๋ฒ | alohaserver4.cafe24.com |
WAR ๋ฐฐํฌ ๊ฒฝ๋ก | /var/www/krules/backend/ |
์ ์ด ์คํฌ๋ฆฝํธ | start.sh / stop.sh / restart.sh |
SSH ์ ์ | Host alias alohaserver4 ์ฌ์ฉ |
Spring Boot๋ ํ์ผ ๋ณต์ฌ๋ง์ผ๋ก ๋๋์ง ์์์. APP.war ์
๋ก๋ โ restart.sh ์๊ฒฉ ์คํ ์์๋ก ๋ฐฐํฌํด์ผ ํด์!
๋ฐฐํฌ ํ์ผ ๊ตฌ์กฐ
๐ย ํ๋ก์ ํธ ๋ฃจํธ/
โโโ ๐ย deploy.bat โ ๋น๋ + ์
๋ก๋ + ์ฌ์์ ์๋ํ
โโโ ๐ย start.bat โ ์๋ฒ ์ฑ ์๊ฒฉ ์์
โโโ ๐ย stop.bat โ ์๋ฒ ์ฑ ์๊ฒฉ ์ข
๋ฃ
โโโ ๐ย restart.bat โ ์๋ฒ ์ฑ ์๊ฒฉ ์ฌ์์
๐ย ์๋ฒ /var/www/krules/backend/
โโโ ๐ปย APP.war โ ๋ฐฐํฌ๋ ์ ํ๋ฆฌ์ผ์ด์
โโโ ๐ย start.sh โ APP.war ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ (๋ก๊ทธ ์ ์ฅ)
โโโ ๐ย stop.sh โ APP.war ํ๋ก์ธ์ค ์ข
๋ฃ
โโโ ๐ย restart.sh โ stop.sh โ start.sh ์์๋ก ์ฌ์์
๐ย ์๋ฒ /var/www/krules/log/
โโโ ๐ฐย appwar_20260422_120000.log โ ์คํ ๋ก๊ทธ (start.sh ์๋ ์์ฑ)
Plain Text
๋ณต์ฌ
์ฌ์ ์ค๋น: ์๋ฒ ๋๋ ํ ๋ฆฌ ์์ฑ (์ต์ด 1ํ)
# ์๋ฒ ์ ์
ssh alohaserver4
# ๋ฐฐํฌ ๊ฒฝ๋ก ์์ฑ
mkdir -p /var/www/krules/backend
mkdir -p /var/www/krules/log
Bash
๋ณต์ฌ
start.sh
#!/bin/bash
# ํ์ฌ ์คํฌ๋ฆฝํธ๊ฐ ์์นํ ๊ฒฝ๋ก๋ก ์ด๋
cd "$(dirname "$0")"
# ๋ก๊ทธ ๋๋ ํ ๋ฆฌ ์์ฑ
LOG_DIR="../log"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/appwar_$(date +%Y%m%d_%H%M%S).log"
# JAVA_HOME์ด ์ค์ ๋์ด ์์ง ์์ผ๋ฉด java ๋ช
๋ น์ด ์ฌ์ฉ
JAVA_CMD=${JAVA_HOME:-}/bin/java
if [ ! -x "$JAVA_CMD" ]; then
JAVA_CMD=java
fi
# JVM ๋ฉ๋ชจ๋ฆฌ ์ ํ (์ต์ 128MB, ์ต๋ 256MB)
JAVA_OPTS="-Xms128m -Xmx256m"
# Spring ํ๋กํ์ผ ๋ช
์ (server = ์ค์๋ฒ ์ค์ , local = ๋ก์ปฌ ๊ฐ๋ฐ)
SPRING_OPTS="--spring.profiles.active=server"
# APP.war ํ์ผ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ๊ณ ๋ก๊ทธ ์ ์ฅ
$JAVA_CMD $JAVA_OPTS -jar APP.war $SPRING_OPTS > "$LOG_FILE" 2>&1 &
JavaScript
๋ณต์ฌ
stop.sh
#!/bin/bash
# APP.war ํ๋ก์ธ์ค ์ข
๋ฃ ์คํฌ๋ฆฝํธ
# ํ์ฌ ๊ฒฝ๋ก์ APP.war ํ๋ก์ธ์ค๋ง ์ข
๋ฃ
cd "$(dirname "$0")"
APP_PATH="$(pwd)/APP.war"
PIDS=$(ps -ef | grep '[j]ava.*-jar' | grep "$APP_PATH" | awk '{print $2}')
if [ -z "$PIDS" ]; then
echo "์คํ ์ค์ธ APP.war ํ๋ก์ธ์ค๊ฐ ์์ต๋๋ค."
exit 0
fi
for PID in $PIDS; do
echo "APP.war ํ๋ก์ธ์ค ์ข
๋ฃ: $PID"
kill $PID
sleep 1
if ps -p $PID > /dev/null; then
echo "๊ฐ์ ์ข
๋ฃ: $PID"
kill -9 $PID
fi
echo "์ข
๋ฃ ์๋ฃ: $PID"
sleep 1
done
echo "๋ชจ๋ APP.war ํ๋ก์ธ์ค๊ฐ ์ข
๋ฃ๋์์ต๋๋ค."
JavaScript
๋ณต์ฌ
restart.sh (ํ๋ก์ ํธ ๋ฃจํธ์ ์ ์ฅ)
start.sh์ stop.sh๋ฅผ ์์๋๋ก ํธ์ถํ๋ ์ฌ์์ ์คํฌ๋ฆฝํธ์์.
#!/bin/bash
# APP.war ์ฌ์์ ์คํฌ๋ฆฝํธ (stop.sh โ start.sh ์์๋ก ์คํ)
cd "$(dirname "$0")"
echo "=== APP.war ์ฌ์์ ์์ ==="
# ๊ธฐ์กด ํ๋ก์ธ์ค ์ข
๋ฃ
bash stop.sh
# ํ๋ก์ธ์ค ์์ ์ข
๋ฃ ๋๊ธฐ
sleep 2
# ์ ํ๋ก์ธ์ค ์์
bash start.sh
echo "=== APP.war ์ฌ์์ ์๋ฃ ==="
Bash
๋ณต์ฌ
1๋จ๊ณ: ์๋ ๋ฐฐํฌ
flowchart TB
A["๐ป ๋ก์ปฌ<br>gradlew clean bootWar"] -->|"APP.war ์์ฑ"| B["๐ฆ APP.war"]
B -->|"scp ์
๋ก๋<br>WAR + sh ํ์ผ"| C["๐ฅ๏ธ ์๋ฒ<br>/var/www/krules/backend/"]
C -->|"plink restart.sh"| D["๐ Spring Boot ์ฌ์์"]
D --> E["๐ ๋ธ๋ผ์ฐ์ ํ์ธ"]Mermaid
๋ณต์ฌ
# 1. ๋ก์ปฌ์์ WAR ๋น๋
./gradlew clean bootWar
# ๋น๋ ๊ฒฐ๊ณผ ํ์ธ
ls build/libs/
# APP.war ํ์ผ ์์ฑ๋จ
# 2. ์๋ฒ์ APP.war + sh ํ์ผ ์
๋ก๋
scp build/libs/APP.war alohaserver4:/var/www/krules/backend/APP.war
scp start.sh stop.sh restart.sh alohaserver4:/var/www/krules/backend/
# 3. sh ํ์ผ ์คํ ๊ถํ ๋ถ์ฌ (์ต์ด 1ํ)
ssh alohaserver4 "chmod +x /var/www/krules/backend/*.sh"
# 4. restart.sh ์๊ฒฉ ์คํ
ssh alohaserver4 "cd /var/www/krules/backend && bash restart.sh"
# 5. ๋ก๊ทธ ํ์ธ
ssh alohaserver4 "tail -f /var/www/krules/log/appwar_*.log"
Bash
๋ณต์ฌ
2๋จ๊ณ: ํ๋ก ํธ์๋ .env ํ๊ฒฝ๋ณ์ ์ค์
๋ฐฑ์๋ API ์ฃผ์๋ฅผ ํ๊ฒฝ์ ๋ฐ๋ผ ๋ถ๋ฆฌํด์ ๊ด๋ฆฌํด์. Vite ํ๋ก์ ํธ๋ VITE_ ์ ๋์ฌ, CRA๋ REACT_APP_ ์ ๋์ฌ๋ฅผ ๋ถ์ฌ์ผ ์ธ์ํด์.
# .env.local (๋ก์ปฌ ๊ฐ๋ฐ์ฉ โ .gitignore์ ์ถ๊ฐ ๊ถ์ฅ)
VITE_API_URL=http://localhost:8080/api
# VITE_API_URL=http://192.168.30.19:8080/api # ๊ฐ์ ๋คํธ์ํฌ ๋ค๋ฅธ PC ํ
์คํธ
# .env.production (๋ฐฐํฌ์ฉ)
# ๋ฐฉ์ A (์๋ธ๋๋ฉ์ธ): api.๊ตญ๋ฃฐ.com โ Spring Boot
# VITE_API_URL=http://xn--3e0b91t.com/api # HTTP ์ ์ฉ ์
# VITE_API_URL=https://api.xn--3e0b91t.com/api # HTTPS ์ ์ฉ ํ
# ๋ฐฉ์ B (๋ฆฌ๋ฒ์ค ํ๋ก์): ๊ตญ๋ฃฐ.com/api โ Spring Boot
# VITE_API_URL=http://xn--3e0b91t.com/api # HTTP ์ ์ฉ ์
# VITE_API_URL=https://xn--3e0b91t.com/api # HTTPS ์ ์ฉ ํ
Bash
๋ณต์ฌ
React ์ฝ๋์์ ์ด๋ ๊ฒ ์ฌ์ฉํด์:
// ํ๊ฒฝ๋ณ์๋ก API ์ฃผ์๋ฅผ ์ฝ์ด์ด
const res = await fetch(`${import.meta.env.VITE_API_URL}/products`);
JavaScript
๋ณต์ฌ
3๋จ๊ณ: Nginx ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ค์ โ ๋ฐฉ์ ์ ํ
๋ ๊ฐ์ง ๋ฐฉ์์ด ์์ด์. ์ํฉ์ ๋ง๊ฒ ํ๋๋ฅผ ์ ํํ์ธ์!
graph TD
A["๐ ์ฌ์ฉ์ ์์ฒญ"] --> B{๋ฐฉ์ ์ ํ}
B -->|"๋ฐฉ์ A<br>์๋ธ๋๋ฉ์ธ"| C["api.๊ตญ๋ฃฐ.com<br>โ Spring Boot :8080"]
B -->|"๋ฐฉ์ B<br>๋ฆฌ๋ฒ์ค ํ๋ก์"| D["๊ตญ๋ฃฐ.com/api/**<br>โ Spring Boot :8080"]
C --> E["๐ Spring Boot"]
D --> EMermaid
๋ณต์ฌ
๋น๊ต | ๋ฐฉ์ A โ ์๋ธ๋๋ฉ์ธ | ๋ฐฉ์ B โ ๊ฒฝ๋ก ๊ธฐ๋ฐ ๋ฆฌ๋ฒ์ค ํ๋ก์ |
API URL | api.๊ตญ๋ฃฐ.com/api/... | ๊ตญ๋ฃฐ.com/api/... |
DNS ์ค์ | api ์๋ธ๋๋ฉ์ธ A๋ ์ฝ๋ ์ถ๊ฐ ํ์ | ์ถ๊ฐ DNS ๋ถํ์ |
SSL ์ธ์ฆ์ | api ์๋ธ๋๋ฉ์ธ ์ธ์ฆ์ ๋ณ๋ ๋ฐ๊ธ | ๊ธฐ์กด ๋๋ฉ์ธ ์ธ์ฆ์ ๊ณต์ |
Nginx ํ์ผ ์ | 2๊ฐ (ํ๋ก ํธ + ๋ฐฑ์๋ ๊ฐ๊ฐ) | 1๊ฐ (ํ๋์ server ๋ธ๋ก์ ํตํฉ) |
์ถ์ฒ ์ํฉ | API ์๋ฒ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ๋ | ๋๋ฉ์ธ ํ๋๋ก ํ์คํ์ ๋จ์ํ๊ฒ ๊ตฌ์ฑํ ๋ |
๋ฐฉ์ A โ ์๋ธ๋๋ฉ์ธ (api.๊ตญ๋ฃฐ.com)
ssh alohaserver4
nano /etc/nginx/conf.d/krules-backend.conf
Bash
๋ณต์ฌ
# ๋ฐฑ์๋ ์ ์ฉ ์๋ฒ ๋ธ๋ก (api ์๋ธ๋๋ฉ์ธ)
server {
listen 80;
server_name api.xn--3e0b91t.com;
location / {
proxy_pass <http://localhost: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;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
client_max_body_size 10M;
}
Plain Text
๋ณต์ฌ
ํ๋ก ํธ์๋ .env.production:
VITE_API_URL=https://api.xn--3e0b91t.com/api
Bash
๋ณต์ฌ
๋ฐฉ์ B โ ๊ฒฝ๋ก ๊ธฐ๋ฐ ๋ฆฌ๋ฒ์ค ํ๋ก์ (๊ตญ๋ฃฐ.com/api)
ํ๋ก ํธ์๋์ ๋ฐฑ์๋๋ฅผ ํ๋์ Nginx ์๋ฒ ๋ธ๋ก์์ ์ฒ๋ฆฌํด์. ๋๋ฉ์ธ ํ๋๋ก ํ์คํ ๊ตฌ์ฑํ ๋ ํธํด์!
ssh alohaserver4
nano /etc/nginx/conf.d/krules.conf
Bash
๋ณต์ฌ
server {
listen 80;
server_name xn--3e0b91t.com www.xn--3e0b91t.com;
# โโ ํ๋ก ํธ์๋ (React Vite ์ ์ ํ์ผ) โโโโโโโโโโโโโโโโโโ
root /var/www/krules/frontend;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# โโ ๋ฐฑ์๋ (Spring Boot ๋ฆฌ๋ฒ์ค ํ๋ก์) โโโโโโโโโโโโโโโโโ
# /api/ ๋ก ์์ํ๋ ์์ฒญ์ Spring Boot๋ก ์ ๋ฌ
location /api/ {
proxy_pass <http://localhost:8080>; # โ /api/ ๊ฒฝ๋ก ๊ทธ๋๋ก ์ ๋ฌ
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;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
client_max_body_size 10M;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
}
Plain Text
๋ณต์ฌ
proxy_pass <http://localhost:8080>; โ ๋์ / ๋ฅผ ๋ถ์ด์ง ์์ผ๋ฉด /api/ ๊ฒฝ๋ก๊ฐ ๊ทธ๋๋ก Spring Boot์ ์ ๋ฌ๋ผ์. Spring Boot์ RequestMapping๋ /api/... ๋ก ๋ง์ถฐ์ผ ํด์!
ํ๋ก ํธ์๋ .env.production:
VITE_API_URL=https://xn--3e0b91t.com/api
Bash
๋ณต์ฌ
nginx -t && systemctl reload nginx
Bash
๋ณต์ฌ
3๋จ๊ณ: ๊ฐ๋ณ ์ ์ด bat ํ์ผ (์๋ฒ ๊ด๋ฆฌ์ฉ)
PuTTY์ plink.exe(์๊ฒฉ ๋ช
๋ น), pscp.exe(ํ์ผ ๋ณต์ฌ)๋ฅผ ์ฌ์ฉํด์.
์ค์น: https://www.putty.org/ โ ๋ค์ด๋ก๋ ํ PATH์ ์ถ๊ฐํ๊ฑฐ๋ bat ํ์ผ๊ณผ ๊ฐ์ ํด๋์ ๋์ธ์.
start.bat
@echo off
chcp 65001 > nul
set REMOTE_USER=root
set REMOTE_HOST=alohaserver4.cafe24.com
set REMOTE_PATH=/var/www/krules/backend
:: ๐ ๋น๋ฐ๋ฒํธ ์
๋ ฅ (์ ๋ณด์ด๊ฒ)
for /f "delims=" %%p in ('powershell -Command "$p = Read-Host ''SSH Password'' -AsSecureString; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($p); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"') do set REMOTE_PASS=%%p
echo [START] Spring Boot ์ฑ ์์ ์ค...
plink -pw %REMOTE_PASS% %REMOTE_USER%@%REMOTE_HOST% "cd %REMOTE_PATH% && bash start.sh"
echo ์๋ฃ!
pause
Shell
๋ณต์ฌ
stop.bat
@echo off
chcp 65001 > nul
set REMOTE_USER=root
set REMOTE_HOST=alohaserver4.cafe24.com
set REMOTE_PATH=/var/www/krules/backend
:: ๐ ๋น๋ฐ๋ฒํธ ์
๋ ฅ (์ ๋ณด์ด๊ฒ)
for /f "delims=" %%p in ('powershell -Command "$p = Read-Host ''SSH Password'' -AsSecureString; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($p); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"') do set REMOTE_PASS=%%p
echo [STOP] Spring Boot ์ฑ ์ข
๋ฃ ์ค...
plink -pw %REMOTE_PASS% %REMOTE_USER%@%REMOTE_HOST% "cd %REMOTE_PATH% && bash stop.sh"
echo ์๋ฃ!
pause
Shell
๋ณต์ฌ
restart.bat
@echo off
chcp 65001 > nul
set REMOTE_USER=root
set REMOTE_HOST=alohaserver4.cafe24.com
set REMOTE_PATH=/var/www/krules/backend
:: ๐ ๋น๋ฐ๋ฒํธ ์
๋ ฅ (์ ๋ณด์ด๊ฒ)
for /f "delims=" %%p in ('powershell -Command "$p = Read-Host ''SSH Password'' -AsSecureString; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($p); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"') do set REMOTE_PASS=%%p
echo [RESTART] Spring Boot ์ฑ ์ฌ์์ ์ค...
plink -pw %REMOTE_PASS% %REMOTE_USER%@%REMOTE_HOST% "cd %REMOTE_PATH% && bash restart.sh"
echo ์๋ฃ!
pause
Shell
๋ณต์ฌ
4๋จ๊ณ: ํตํฉ ๋ฐฐํฌ ์๋ํ (deploy.bat)
clean bootWar โ APP.war + sh ํ์ผ ์
๋ก๋ โ restart.sh ์๊ฒฉ ์คํ๊น์ง ํ ๋ฒ์!
deploy.bat
@echo off
chcp 65001 > nul
echo.
echo =============================================
echo Spring Boot bootWar Build ^& Deploy
echo =============================================
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: ์ค์ ๊ฐ
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
set PROJECT_DIR=%~dp0
set REMOTE_USER=root
set REMOTE_HOST=alohaserver4.cafe24.com
set REMOTE_PATH=/var/www/krules/backend
:: ๐ ๋น๋ฐ๋ฒํธ ์
๋ ฅ (์ ๋ณด์ด๊ฒ)
for /f "delims=" %%p in ('powershell -Command "$p = Read-Host ''SSH Password'' -AsSecureString; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($p); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"') do set REMOTE_PASS=%%p
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [1] bootWar ๋น๋
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo [1/3] bootWar ๋น๋ ์ค...
cd /d %PROJECT_DIR%
call gradlew.bat clean bootWar
if errorlevel 1 (
echo.
echo [์ค๋ฅ] ๋น๋ ์คํจ! ์๋ฌ๋ฅผ ํ์ธํ์ธ์.
pause
exit /b 1
)
echo ๋น๋ ์๋ฃ - APP.war ์์ฑ๋จ
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [2] ํ์ผ ์
๋ก๋
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo [2/3] ํ์ผ ์
๋ก๋ ์ค...
pscp -pw %REMOTE_PASS% build\libs\APP.war %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_PATH%/APP.war
if errorlevel 1 (
echo.
echo [์ค๋ฅ] WAR ์
๋ก๋ ์คํจ!
pause
exit /b 1
)
pscp -pw %REMOTE_PASS% start.sh stop.sh restart.sh %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_PATH%/
echo ์
๋ก๋ ์๋ฃ
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [3] ์๋ฒ ์ฌ์์
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo [3/3] ์๋ฒ ์ฌ์์ ์ค...
plink -pw %REMOTE_PASS% %REMOTE_USER%@%REMOTE_HOST% "chmod +x %REMOTE_PATH%/*.sh && cd %REMOTE_PATH% && bash restart.sh"
if errorlevel 1 (
echo.
echo [์ค๋ฅ] ์ฌ์์ ์คํจ!
pause
exit /b 1
)
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [4] ์๋ฃ
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo.
echo =============================================
echo ๋ฐฐํฌ ์๋ฃ!
echo ๋ก๊ทธ ํ์ธ:
echo ssh %REMOTE_USER%@%REMOTE_HOST%
echo tail -f /var/www/krules/log/appwar_*.log
echo =============================================
echo.
pause
Shell
๋ณต์ฌ
์คํ ๋ฐฉ๋ฒ: deploy.bat ๋๋ธํด๋ฆญ โ bootWar ๋น๋ โ WAR + sh ์
๋ก๋ โ restart.sh ์คํ๊น์ง ์๋!
(์ ํ) SSH ํค ์ธ์ฆ์ผ๋ก ๋น๋ฐ๋ฒํธ ์์ด ๋ฐฐํฌ
# 1. SSH ํค ์์ฑ (์ด๋ฏธ ์์ผ๋ฉด ์๋ต)
ssh-keygen -t ed25519 -C "deploy-key"
# 2. ๊ณต๊ฐํค๋ฅผ ์๋ฒ์ ๋ฑ๋ก
ssh-copy-id alohaserver4
Bash
๋ณต์ฌ
ํค ๋ฑ๋ก ํ ๊ฐ bat ํ์ผ์์ pscp -pw / plink -pw ๋์ ํ์ค ๋ช
๋ น์ผ๋ก ๊ต์ฒด:
:: WAR ์
๋ก๋ (pscp โ scp)
scp build\\libs\\APP.war alohaserver4:%REMOTE_PATH%/APP.war
scp start.sh stop.sh restart.sh alohaserver4:%REMOTE_PATH%/
:: ์๊ฒฉ ์คํ (plink โ ssh)
ssh alohaserver4 "chmod +x %REMOTE_PATH%/*.sh && cd %REMOTE_PATH% && bash restart.sh"
Shell
๋ณต์ฌ
์ฒดํฌ๋ฆฌ์คํธ
~/.ssh/config ์ alohaserver4 Host ์ค์ ์๋ฃ?
์๋ฒ์ /var/www/krules/backend/ ๋ฐ /var/www/krules/log/ ๋๋ ํ ๋ฆฌ ์์ฑ?
ํ๋ก์ ํธ ๋ฃจํธ์ start.sh / stop.sh / restart.sh ํ์ผ ์กด์ฌ?
./gradlew clean bootWar โ build/libs/APP.war ์์ฑ ํ์ธ?
scp APP.war + *.sh ์
๋ก๋ ์ฑ๊ณต?
์๋ฒ์์ chmod +x /var/www/krules/backend/*.sh ์๋ฃ?
ssh alohaserver4 "cd /var/www/krules/backend && bash restart.sh" ์คํ ํ์ธ?
tail -f /var/www/krules/log/appwar_*.log ๋ก ์ ์ ๊ธฐ๋ ๋ก๊ทธ ํ์ธ?
Nginx conf.d/krules-backend.conf ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ค์ ?
nginx -t ํต๊ณผ ๋ฐ systemctl reload nginx ์๋ฃ?
start.bat / stop.bat / restart.bat ๊ฐ๋ณ ๋์ ํ์ธ?
deploy.bat ํตํฉ ๋ฐฐํฌ ํ
์คํธ ์๋ฃ?
ํต์ฌ ์ ๋ฆฌ
Spring Boot = ๋ด์ฅ ํฐ์บฃ์ผ๋ก ์์ฒด ์คํ โ Nginx๋ ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ญํ
systemd ์๋น์ค ๋ฑ๋ก์ผ๋ก ์ฑ ์๋ ์์/์ฌ์์ ๋ณด์ฅ
ํ๋ก์ ํค๋(X-Real-IP, X-Forwarded-For ๋ฑ) ์ค์ ํ์
Spring Boot forward-headers-strategy: framework ์ค์ ํ์
Certbot์ผ๋ก HTTPS ์ ์ฉ + HTTPโHTTPS ๋ฆฌ๋ค์ด๋ ํธ




