React ์ฑ Nginx๋ก ๋ฐฐํฌํ๊ธฐ
๊ฐ์
React ์ฑ์ ๋น๋ ํ ์์ฑ๋๋ ์ ์ ํ์ผ(HTML, CSS, JS)์ Nginx๊ฐ ์ง์ ์๋นํ๋ ๋ฐฉ์์ผ๋ก ๋ฐฐํฌํ๋ค.
React๋ก ๋ง๋ ํ๋ก ํธ์๋ ์ฑ์ ์ค์ ์๋น์ค๋ก ์ฌ๋ฆฌ๋ ค๋ฉด, npm start๋ก ๊ฐ๋ฐ ์๋ฒ๋ฅผ ๋๋ฆฌ๋ ๊ฒ ์๋๋ผ ๋น๋(Build)ํ ๊ฒฐ๊ณผ๋ฌผ์ Nginx๋ก ์๋นํด์ผ ํด์.
React์ npm run build ๋ช
๋ น์ ์คํํ๋ฉด build/ ํด๋์ ์ต์ ํ๋ ์ ์ ํ์ผ๋ค์ด ์๊ฒจ์. ์ด ํ์ผ๋ค์ Nginx์ ์น ๋ฃจํธ์ ์ฌ๋ ค๋์ผ๋ฉด ๋! Nginx๊ฐ HTML, CSS, JS ํ์ผ์ ๊ทธ๋๋ก ์ ๋ฌํด์ฃผ๋ ์ ์ ํ์ผ ์๋ฒ ์ญํ ์ ํ๋ ๊ฑฐ์์.
๋ฐฐํฌ ์ํคํ
์ฒ
graph LR
A[๐ค ์ฌ์ฉ์<br/>๋ธ๋ผ์ฐ์ ] -->|"<https://example.com>"| B[๐ฅ๏ธ Nginx<br/>ํฌํธ 443/80]
B -->|์ ์ ํ์ผ ์๋น| C["๐ /var/www/frontend/<br/>build ๊ฒฐ๊ณผ๋ฌผ<br/>index.html, JS, CSS"]
style B fill:#90EE90
style C fill:#87CEEBMermaid
๋ณต์ฌ
flowchart TD
A["๐ป ๋ก์ปฌ ๊ฐ๋ฐ"] -->|npm run build| B["๐ฆ build/ ํด๋ ์์ฑ"]
B -->|"scp ๋๋ CI/CD"| C["๐ฅ๏ธ ์๋ฒ์ ์
๋ก๋<br/>/var/www/frontend/"]
C --> D["โ๏ธ Nginx ์ค์ <br/>์ ์ ํ์ผ ์๋น"]
D --> E["๐ ์๋น์ค ์คํ!"]
style B fill:#FFD700
style D fill:#90EE90Mermaid
๋ณต์ฌ
Step 1: React ์ฑ ๋น๋
# ๋ก์ปฌ (๊ฐ๋ฐ ํ๊ฒฝ)์์ ๋น๋
cd my-react-app
npm run build
# build/ ํด๋ ๋ด์ฉ ํ์ธ
ls build/
# index.html static/ asset-manifest.json ...
Bash
๋ณต์ฌ
build/ ํด๋์ ๋ง๋ค์ด์ง๋ ํ์ผ:
ํ์ผ/ํด๋ | ์ค๋ช
|
index.html | ์ง์
์ HTML |
static/js/ | ๋ฒ๋ค๋ง๋ JavaScript |
static/css/ | ๋ฒ๋ค๋ง๋ CSS |
static/media/ | ์ด๋ฏธ์ง, ํฐํธ ๋ฑ |
asset-manifest.json | ์์
๋งคํ ์ ๋ณด |
Step 2: ์๋ฒ์ ํ์ผ ์
๋ก๋
# SCP๋ก ๋น๋ ํ์ผ ์
๋ก๋
scp -r build/* ubuntu@์๋ฒIP:/var/www/frontend/
# ๋๋ rsync (๋ ํจ์จ์ โ ๋ณ๊ฒฝ๋ ํ์ผ๋ง ์ ์ก)
rsync -avz --delete build/ ubuntu@์๋ฒIP:/var/www/frontend/
Bash
๋ณต์ฌ
# ์๋ฒ์์ ๋๋ ํ ๋ฆฌ ์์ฑ ๋ฐ ๊ถํ ์ค์
sudo mkdir -p /var/www/frontend
sudo chown -R www-data:www-data /var/www/frontend
Bash
๋ณต์ฌ
Step 3: Nginx ์ค์
sudo nano /etc/nginx/sites-available/react-app
Bash
๋ณต์ฌ
server {
listen 80;
server_name example.com www.example.com;
root /var/www/frontend;
index index.html;
# โญ React Router ๋์ (SPA ํต์ฌ ์ค์ !)
location / {
try_files $uri $uri/ /index.html;
}
# ์ ์ ์์
์บ์ฑ (JS, CSS ๋ฑ)
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# ํ๋น์ฝ 404 ๋ฐฉ์ง
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# gzip ์์ถ
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 256;
}
Plain Text
๋ณต์ฌ
try_files $uri $uri/ /index.html ์ด ๋ญ์ผ?
์ด ์ค์ ์ด React ๋ฐฐํฌ์์ ๊ฐ์ฅ ์ค์ํ ํ ์ค์ด์์!
flowchart TD
A["์ฌ์ฉ์๊ฐ /about ์์ฒญ"] --> B{"ํ์ผ ์์?<br/>/var/www/frontend/about"}
B -->|"์์ ($uri)"| C["ํด๋น ํ์ผ ๋ฐํ"]
B -->|"์์"| D{"ํด๋ ์์?<br/>/var/www/frontend/about/"}
D -->|"์์ ($uri/)"| E["ํด๋์ index ๋ฐํ"]
D -->|"์์"| F["๐ /index.html ๋ฐํ<br/>React Router๊ฐ ์ฒ๋ฆฌ!"]
style F fill:#90EE90Mermaid
๋ณต์ฌ
React๋ SPA(Single Page Application)์ด๋ผ์, /about, /users/123 ๊ฐ์ ๊ฒฝ๋ก๊ฐ ์ค์ ํ์ผ๋ก ์กด์ฌํ์ง ์์์. ๋ชจ๋ ๋ผ์ฐํ
์ JavaScript(React Router)๊ฐ ์ฒ๋ฆฌํ๊ฑฐ๋ ์.
๊ทธ๋์ ํ์ผ์ด ์์ ๋ 404๋ฅผ ๋ฐํํ๋ ๋์ , index.html์ ๋ฐํํด์ React Router๊ฐ ์ฒ๋ฆฌํ๋๋ก ํ๋ ๊ฑฐ์์!
Step 4: ์ฌ์ดํธ ํ์ฑํ
# ์ฌ๋ณผ๋ฆญ ๋งํฌ๋ก ํ์ฑํ
sudo ln -s /etc/nginx/sites-available/react-app /etc/nginx/sites-enabled/
# ๊ธฐ๋ณธ ์ฌ์ดํธ ๋นํ์ฑํ (์ถฉ๋ ๋ฐฉ์ง)
sudo rm /etc/nginx/sites-enabled/default
# ์ค์ ํ
์คํธ
sudo nginx -t
# ์ ์ฉ
sudo systemctl reload nginx
Bash
๋ณต์ฌ
Step 5: HTTPS ์ ์ฉ
# Certbot์ผ๋ก SSL ์๋ ์ค์
sudo certbot --nginx -d example.com -d www.example.com
Bash
๋ณต์ฌ
HTTPS ์ ์ฉ ํ ์ต์ข
์ค์ :
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/frontend;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
}
# HTTP โ HTTPS ๋ฆฌ๋ค์ด๋ ํธ
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Plain Text
๋ณต์ฌ
์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์
๋ฌธ์ | ์์ธ | ํด๊ฒฐ |
์๋ก๊ณ ์นจํ๋ฉด 404 | try_files ๋ฏธ์ค์ | try_files $uri $uri/ /index.html ์ถ๊ฐ |
ํฐ ํ๋ฉด (๋น ํ์ด์ง) | homepage ๊ฒฝ๋ก ๋ถ์ผ์น | package.json์ homepage ํ์ธ |
CSS/JS ๋ก๋ฉ ์ ๋จ | root ๊ฒฝ๋ก ์ค๋ฅ | root ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก ํ์ธ |
403 Forbidden | ํ์ผ ๊ถํ ๋ฌธ์ | chown -R www-data:www-data /var/www/frontend |
์บ์๋ ์๋ ๋ฒ์ ํ์ | ๋ธ๋ผ์ฐ์ ์บ์ | ๊ฐ๋ ฅ ์๋ก๊ณ ์นจ (Ctrl+Shift+R) |
์ค์ต
์ค์ต ํ๊ฒฝ
ํญ๋ชฉ | ๊ฐ |
๋ก์ปฌ ํ๋ก์ ํธ | Vite ๊ธฐ๋ฐ React ์ฑ |
๋น๋ ๊ฒฐ๊ณผ ํด๋ | dist/ |
์๋ฒ | alohaserver4.cafe24.com |
๋ฐฐํฌ ๊ฒฝ๋ก | /var/www/krules/frontend |
SSH ์ ์ | Host alias alohaserver4 ์ฌ์ฉ |
Vite๋ ๋น๋ ๊ฒฐ๊ณผ๊ฐ build/ ๊ฐ ์๋๋ผ dist/ ํด๋์ ์์ฑ๋ผ์. CRA(Create React App)๊ณผ ๋ค๋ฅธ ์ ์ด์์!
SSH Config ์ค์ (~/.ssh/config)
ํฐ๋ฏธ๋์์ ๋งค๋ฒ ๊ธด ์ฃผ์๋ฅผ ์น๋ ๋์ ๋ณ๋ช
(alias)์ผ๋ก ์ ์ํ ์ ์์ด์.
# ~/.ssh/config
Host alohaserver4
HostName alohaserver4.cafe24.com
User root
Plain Text
๋ณต์ฌ
์ค์ ํ ์ด๋ ๊ฒ ์งง๊ฒ ์ ์:
ssh alohaserver4 # root@alohaserver4.cafe24.com ๊ณผ ๋์ผ
Bash
๋ณต์ฌ
1๋จ๊ณ: ์๋ ๋ฐฐํฌ (SSH + SCP)
flowchart LR
A["๐ป ๋ก์ปฌ\\nnpm run build"] -->|"dist/ ์์ฑ"| B["๐ฆ dist/ ํด๋"]
B -->|"scp ์
๋ก๋"| C["๐ฅ๏ธ ์๋ฒ\\n/var/www/krules/frontend/"]
C --> D["๐ ๋ธ๋ผ์ฐ์ ํ์ธ"]Mermaid
๋ณต์ฌ
# 1. ๋ก์ปฌ์์ ๋น๋ (Vite โ dist/)
npm run build
# 2. ์๋ฒ์ ๋ฐฐํฌ ๊ฒฝ๋ก ์์ฑ (์ต์ด 1ํ)
ssh root@alohaserver4.cafe24.com "mkdir -p /var/www/krules/frontend"
# 3. dist/ ๋ด์ฉ ์๋ฒ๋ก ์
๋ก๋
# (dist/* ๋ก dist ํด๋ ์์ฒด๊ฐ ์๋ ๋ด์ฉ๋ฌผ๋ง ๋ณต์ฌ)
scp -r dist/* root@alohaserver4.cafe24.com:/var/www/krules/frontend/
# 4. ์๋ฒ์์ ํ์ผ ํ์ธ
ssh root@alohaserver4.cafe24.com "ls -la /var/www/krules/frontend/"
Bash
๋ณต์ฌ
2๋จ๊ณ: Nginx ์ค์ (์๋ฒ์์)
# ์๋ฒ ์ ์
ssh root@alohaserver4.cafe24.com
# ์ค์ ํ์ผ ์์ฑ - ๋ฐฉ๋ฒ1 (conf.d)
nano /etc/nginx/conf.d/krules.conf
# ์ค์ ํ์ผ ์์ฑ - ๋ฐฉ๋ฒ2 (sites-available)
nano /etc/nginx/sites-available/krules.conf
# sites-available โ sites-enabled ์ฌ๋ณผ๋ฆญ ๋งํฌ
sudo ln -s /etc/nginx/sites-available/krules.conf /etc/nginx/sites-enabled/
Bash
๋ณต์ฌ
server {
listen 80;
server_name xn--3e0b91t.com www.xn--3e0b91t.com;
root /var/www/krules/frontend;
index index.html;
# SPA ๋ผ์ฐํ
๋์
location / {
try_files $uri $uri/ /index.html;
}
# Vite ๋น๋ ์์
์บ์ฑ (assets/ ํด๋์ hash ํ์ผ๋ช
์ผ๋ก ์์ฑ๋จ)
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
}
Plain Text
๋ณต์ฌ
sudo nginx -t && systemctl reload nginx
Bash
๋ณต์ฌ
3๋จ๊ณ: .bat ํ์ผ๋ก ๋ฐฐํฌ ์๋ํ
๋งค๋ฒ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ ๊ฒ ๊ท์ฐฎ์ผ๋๊น ํด๋ฆญ ํ ๋ฒ์ผ๋ก ๋น๋ + ๋ฐฐํฌ๊น์ง ์๋ํํด์!
๋น๋ฐ๋ฒํธ ์๋ ์
๋ ฅ์ ์ํด PuTTY์ pscp.exe ๋ฅผ ์ฌ์ฉํด์.
์ค์น: https://www.putty.org/ โ pscp.exe ๋ค์ด๋ก๋ ํ PATH์ ์ถ๊ฐํ๊ฑฐ๋ bat ํ์ผ๊ณผ ๊ฐ์ ํด๋์ ๋์ธ์.
๋๋ SSH ํค ์ธ์ฆ์ ์ค์ ํ๋ฉด ๋น๋ฐ๋ฒํธ ์์ด ์ผ๋ฐ scp ์ฌ์ฉ ๊ฐ๋ฅ (๋ ์์ , ์๋ ์ฐธ๊ณ )
deploy.bat (ํ๋ก์ ํธ ๋ฃจํธ์ ์ ์ฅ)
@echo off
chcp 65001 > nul
echo.
echo =============================================
echo React Vite Build ^& Deploy to alohaserver4
echo =============================================
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: ์ค์ ๊ฐ
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
set PROJECT_DIR=%~dp0
set REMOTE_USER=root
set REMOTE_HOST=alohaserver4.cafe24.com
set REMOTE_PATH=/var/www/krules/frontend/
:: ๐ ๋น๋ฐ๋ฒํธ ์
๋ ฅ (์ ๋ณด์ด๊ฒ)
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] ๋น๋
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo [1/2] ๋น๋ ์ค...
cd /d %PROJECT_DIR%
call npm run build
if errorlevel 1 (
echo.
echo [์ค๋ฅ] ๋น๋ ์คํจ! ์๋ฌ๋ฅผ ํ์ธํ์ธ์.
pause
exit /b 1
)
echo ๋น๋ ์๋ฃ - dist/ ํด๋ ์์ฑ๋จ
echo.
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [2] ์๋ฒ ์
๋ก๋
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo [2/2] ์๋ฒ์ ์
๋ก๋ ์ค...
pscp -pw %REMOTE_PASS% -r dist\* %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_PATH%
if errorlevel 1 (
echo.
echo [์ค๋ฅ] ์
๋ก๋ ์คํจ! ์๋ฒ ์ฐ๊ฒฐ์ ํ์ธํ์ธ์.
pause
exit /b 1
)
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
:: [3] ์๋ฃ
:: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
echo.
echo =============================================
echo ๋ฐฐํฌ ์๋ฃ!
echo http://xn--3e0b91t.com ์์ ํ์ธํ์ธ์.
echo =============================================
echo.
pause
Shell
๋ณต์ฌ
์คํ ๋ฐฉ๋ฒ: deploy.bat ๋๋ธํด๋ฆญ โ ๋น๋ + ์
๋ก๋ ์๋ ์งํ
(์ ํ) SSH ํค ์ธ์ฆ์ผ๋ก ๋น๋ฐ๋ฒํธ ์์ด ๋ฐฐํฌ
๋น๋ฐ๋ฒํธ๋ฅผ ํ์ผ์ ์ ์ฅํ๋ ๊ฑด ๋ณด์์ ์ข์ง ์์์. SSH ํค๋ฅผ ์ค์ ํ๋ฉด ๋น๋ฐ๋ฒํธ ์์ด ๋ ์์ ํ๊ฒ ์๋ํํ ์ ์์ด์.
# Windows PowerShell ๋๋ CMD์์
# 1. SSH ํค ์์ฑ (์ด๋ฏธ ์์ผ๋ฉด ์๋ต)
ssh-keygen -t ed25519 -C "deploy-key"
# 2. ๊ณต๊ฐํค๋ฅผ ์๋ฒ์ ๋ฑ๋ก
ssh-copy-id alohaserver4
# ๋๋ ์ง์ ๋ถ์ฌ๋ฃ๊ธฐ:
# type %USERPROFILE%\\.ssh\\id_ed25519.pub | ssh alohaserver4 "cat >> ~/.ssh/authorized_keys"
Bash
๋ณต์ฌ
ํค ๋ฑ๋ก ํ deploy.bat ์์ pscp -pw ๋์ ์ผ๋ฐ scp ์ฌ์ฉ:
:: pscp ์ค์ ์๋๋ก ๊ต์ฒด
scp -r dist\\* alohaserver4:%REMOTE_PATH%
Shell
๋ณต์ฌ
์ฒดํฌ๋ฆฌ์คํธ
~/.ssh/config ์ alohaserver4 Host ์ค์ ์๋ฃ?
ssh alohaserver4 ์ ์ ํ์ธ?
์๋ฒ์ /var/www/krules/frontend ๋๋ ํ ๋ฆฌ ์์ฑ?
npm run build โ dist/ ํด๋ ์์ฑ ํ์ธ?
scp -r dist/* alohaserver4:/var/www/krules/frontend/ ์
๋ก๋ ์ฑ๊ณต?
Nginx conf.d/krules.conf ์ค์ ์๋ฃ?
try_files $uri $uri/ /index.html ํฌํจ?
nginx -t ํต๊ณผ ๋ฐ systemctl reload nginx ์๋ฃ?
๋ธ๋ผ์ฐ์ ์์ ์ ์ ํ์ธ?
deploy.bat ์์ฑ ํ ์๋ ๋ฐฐํฌ ํ
์คํธ?
ํต์ฌ ์ ๋ฆฌ
React ๋ฐฐํฌ = npm run build โ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ Nginx๋ก ์ ์ ์๋น
ํต์ฌ ์ค์ : try_files $uri $uri/ /index.html (SPA ๋ผ์ฐํ
๋์)
์ ์ ์์
(/static/)์๋ ์ฅ๊ธฐ ์บ์ฑ ์ ์ฉ โ ์ฑ๋ฅ ํฅ์
gzip ์์ถ์ผ๋ก ์ ์ก ํฌ๊ธฐ ์ ์ฝ
Certbot์ผ๋ก HTTPS ์ ์ฉ ํ์




