| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 리눅스
- spring security 설정
- java
- Ubuntu서버
- 혼공얄코
- Comparator
- Comparable
- spring security
- AWS배포
- 둘만의 암호
- 티스토리챌린지
- 분할정복
- BFS
- EC2배포
- SQL Mapper
- 스프링부트 배포
- 백트래킹
- 오블완
- 프로그래머스 2개 이하로 다른 비트
- 서버초기설정
- 자바의 정석
- systemd
- 자바의정석
- hackerrank
- springboot
- 분할정복 알고리즘
- 프로그래머스 둘만의 암호
- 프로그래머스
- LocalDate
- 둘만의 암호 자바
- Today
- Total
쉽게 쉽게
[AWS] AWS에 프로젝트 배포하기 (2) - 서비스 실행, Nginx 설정 본문
- init_server.sh로 서버 초기 설정 완료 — 전용 계정 생성·디렉터리 구성·환경변수 파일 생성·systemd 등록·sudo 권한 설정
- 환경변수 파일로 민감 정보 분리 — DB 비밀번호·API 키를 소스코드 밖에서 관리해 GitHub에 올려도 노출되지 않습니다.
- systemd 서비스로 자동 실행·복구 보장 — 서버가 재부팅되거나 앱이 오류로 종료되어도 자동으로 다시 실행됩니다.
- 운영 전 ddl-auto 반드시 validate로 변경 — update 상태로 운영하면 스키마가 변경될 수 있으므로 안정화 후 전환해야 합니다.
5 STEP 5~6 : 서비스 등록 및 환경변수 설정
STEP 5 — 서버 초기 설정 스크립트 실행
이제 실제 서비스를 배포하기 위한 작업을 진행하려고 합니다.
원래라면 서비스 계정 생성, 앱 디렉터리 구성, systemd 서비스 등록까지 하나씩 수동으로 실행해야 하지만 해당 스크립트 하나로 초기 환경 설정을 한 번에 처리하려고 합니다.
init_server.sh 작성예시
#!/usr/bin/env bash
# ============================================================
# Spring Boot 서버 최초 초기 설정 스크립트 (템플릿)
#
# 사용법:
# 1. 아래 [설정 변수] 섹션을 프로젝트에 맞게 수정
# 2. 서버에서 실행: sudo bash init_server.sh
#
# 이 스크립트는 서버를 처음 세팅할 때 딱 한 번만 실행합니다.
# 이후 배포는 deploy-wsl.sh 를 사용합니다.
# ============================================================
set -euo pipefail
info() { echo -e "\033[34m[INFO]\033[0m $*"; }
ok() { echo -e "\033[32m[OK]\033[0m $*"; }
# ============================================================
# ★ 설정 변수 — 이 부분만 프로젝트에 맞게 수정하세요
# ============================================================
PROJECT_NAME="my-project" # 서비스명 (계정명·디렉터리명에 사용됩니다)
APP_DIR="/opt/${PROJECT_NAME}" # 앱 실행 디렉터리 (JAR 파일 위치)
UPLOAD_DIR="/var/${PROJECT_NAME}/uploads" # 파일 업로드 저장 경로
LOG_DIR="/var/log/${PROJECT_NAME}" # 로그 디렉토리
ENV_DIR="/etc/${PROJECT_NAME}" # 환경변수 파일 디렉터리
SERVICE_FILE="${PROJECT_NAME}.service" # systemd 서비스 파일명
# ============================================================
# 필자 변수 예시
#PROJECT_NAME="project"
#APP_DIR="/opt/project"
#UPLOAD_DIR="/var/project/uploads/ministry"
#LOG_DIR="/var/log/project"
#ENV_DIR="/etc/project"
#SERVICE_FILE="project.service"
# ============================================================
# ============================================================
# STEP 1. 전용 실행 계정 생성
# ============================================================
# -r : 시스템 계정으로 생성 (일반 로그인 불가)
# -s /sbin/nologin : SSH 직접 로그인 차단 (보안 강화)
info "STEP 1 — 전용 계정(${PROJECT_NAME}) 생성"
if id "${PROJECT_NAME}" &>/dev/null; then
echo " 이미 존재함, 건너뜀"
else
useradd -r -m -s /sbin/nologin "${PROJECT_NAME}"
ok "계정 생성 완료"
fi
# ============================================================
# STEP 2. 필수 디렉터리 생성 및 권한 설정
# ============================================================
info "STEP 2 — 디렉토리 생성"
# 앱 실행 디렉토리 (JAR 파일이 위치할 경로)
mkdir -p "${APP_DIR}"
chown "${PROJECT_NAME}:${PROJECT_NAME}" "${APP_DIR}"
chmod 750 "${APP_DIR}"
# 파일 업로드 디렉토리
mkdir -p "${UPLOAD_DIR}"
chown -R "${PROJECT_NAME}:${PROJECT_NAME}" "/var/${PROJECT_NAME}"
chmod -R 755 "/var/${PROJECT_NAME}"
# 로그 디렉토리
mkdir -p "${LOG_DIR}"
chown "${PROJECT_NAME}:${PROJECT_NAME}" "${LOG_DIR}"
chmod 750 "${LOG_DIR}"
ok "디렉터리 생성 완료"
# ============================================================
# STEP 3. 환경변수 파일 초기화
# ============================================================
# 민감 정보(DB 비밀번호, API 키 등)를 소스코드와 분리해 관리합니다.
# chmod 600 으로 소유자만 읽을 수 있도록 보호합니다.
info "STEP 3 — 환경변수 파일 생성"
mkdir -p "${ENV_DIR}"
if [[ -f "${ENV_DIR}/env" ]]; then
echo " 이미 존재함, 건너뜀 (기존 값 유지)"
else
cat > "${ENV_DIR}/env" << 'EOF'
# 이 파일에 프로젝트에서 사용하는 환경변수를 입력하세요.
# 스크립트 실행 후 아래 명령으로 직접 편집합니다:
# sudo nano /etc/[프로젝트명]/env
EOF
chown "${PROJECT_NAME}:${PROJECT_NAME}" "${ENV_DIR}/env"
chmod 600 "${ENV_DIR}/env"
ok "환경변수 파일 생성: ${ENV_DIR}/env"
echo ""
echo " !! 반드시 아래 파일을 열어 실제 값을 입력하세요 !!"
echo " sudo nano ${ENV_DIR}/env"
echo ""
fi
# ============================================================
# STEP 4. systemd 서비스 등록
# ============================================================
# systemd 에 등록하면 서버 재부팅 시 자동으로 앱이 실행됩니다.
# 이 스크립트와 같은 폴더에 .service 파일이 있어야 합니다.
info "STEP 4 — systemd 서비스 등록"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ -f "${SCRIPT_DIR}/${SERVICE_FILE}" ]]; then
cp "${SCRIPT_DIR}/${SERVICE_FILE}" /etc/systemd/system/
systemctl daemon-reload
systemctl enable "${PROJECT_NAME}" # 서버 재부팅 시 자동 시작 등록
ok "서비스 등록 완료 (아직 시작하지 않음)"
else
echo " ${SERVICE_FILE} 파일을 찾을 수 없습니다."
echo " 수동으로 /etc/systemd/system/ 에 복사 후 아래 명령을 실행하세요:"
echo " sudo systemctl daemon-reload && sudo systemctl enable ${PROJECT_NAME}"
fi
# ============================================================
# STEP 5. sudo 권한 설정
# ============================================================
# 전용 계정이 서비스 시작·정지·로그 조회만 할 수 있도록 권한을 제한합니다.
# 전체 sudo 권한을 주지 않아 보안 사고 발생 시 피해 범위를 최소화합니다.
info "STEP 5 — sudo 권한 설정"
SUDOERS_FILE="/etc/sudoers.d/${PROJECT_NAME}"
if [[ ! -f "$SUDOERS_FILE" ]]; then
cat > "$SUDOERS_FILE" << EOF
# ${PROJECT_NAME} 계정이 서비스 제어 명령만 실행할 수 있도록 허용
${PROJECT_NAME} ALL=(ALL) NOPASSWD: /bin/systemctl start ${PROJECT_NAME}
${PROJECT_NAME} ALL=(ALL) NOPASSWD: /bin/systemctl stop ${PROJECT_NAME}
${PROJECT_NAME} ALL=(ALL) NOPASSWD: /bin/systemctl restart ${PROJECT_NAME}
${PROJECT_NAME} ALL=(ALL) NOPASSWD: /bin/journalctl -u ${PROJECT_NAME} *
EOF
chmod 440 "$SUDOERS_FILE"
ok "sudo 권한 설정 완료"
fi
# ============================================================
# 완료
# ============================================================
echo ""
echo "=============================================="
ok "서버 초기 설정 완료"
echo "=============================================="
echo ""
echo "다음 단계:"
echo " 1. 환경변수 파일에 실제 값 입력"
echo " sudo nano ${ENV_DIR}/env"
echo ""
echo " 2. JAR 파일을 서버로 전송한 뒤 서비스 시작"
echo " sudo systemctl start ${PROJECT_NAME}"
echo ""
echo " 3. 서비스 상태 확인"
echo " sudo systemctl status ${PROJECT_NAME}"
echo " sudo journalctl -u ${PROJECT_NAME} -f"
# ============================================================
해당 스크립트 작성에 대한 자세한 내용은 아래 글을 참고하시길 바랍니다.
2026.06.19 - [프로젝트 경험] - [AWS] AWS에 프로젝트 배포하기 (1) - EC2 생성, 초기 설정, 배포 준비
[AWS] AWS에 프로젝트 배포하기 (1) - EC2 생성, 초기 설정, 배포 준비
📌 핵심 요약EC2 단일 인스턴스 — 컨테이너 없이 Spring Boot + MySQL + Nginx를 한 서버에 구성t4g.small (ARM) 추천 — Java 21 + MySQL 동시 운영 시 메모리 여유, x86 대비 약 20% 저렴월 $10~12 수준 — 하루 12시
minsu092274.tistory.com
프로젝트의 deploy 폴더 내에 init_server.sh 파일과 project.service가 작성완료됐다고 생각하고 다음 단계를 진행하겠습니다.
scp(Secure Copy)는 SSH를 이용해 로컬과 원격 서버 간에 파일을 안전하게 복사하는 명령어입니다.
프로젝트의 deploy 폴더 전체를 서버 홈 디렉터리(~/)로 전송한 뒤 스크립트를 실행합니다.
# WSL에서 서버로 전송
scp -i "~/.ssh/[저장한 이름.pem]" -r ./deploy ubuntu@[IP]:~/
# 서버에서 실행
sudo bash ~/deploy/init_server.sh
STEP 6 — 환경변수 파일 설정
init_server.sh에서 대부분의 처리를 했지만 DB 비밀번호나 API 키 같은 민감한 정보는 소스코드에 직접 작성하지 않고 환경변수 파일로 별도 관리합니다.
init_server.sh에서 etc/[프로젝트명]/env 파일을 만들어 환경변수를 저장하도록 구현되어 있습니다.
여기에 민감한 정보를 직접 입력하여 저장하면 됩니다.(DB 계정/비밀번호, API 비밀번호 등)
이 파일은 chmod 600으로 보호되어 오직 소유자만 읽고 쓸 수 있습니다.
소스코드가 GitHub에 올라가더라도 민감한 정보가 노출되지 않습니다.
sudo nano /etc/[프로젝트명]/env
nano는 터미널에서 사용하는 텍스트 편집기입니다. 파일이 열리면 아래 내용을 작성합니다.
DB_USERNAME=실제DB계정명
DB_PASSWORD=실제비밀번호
UPLOAD_DIR=/var/실제경로/uploads
Ctrl + O → Enter (저장) → Ctrl + X (종료)
6 STEP 7~8 : JAR 빌드 및 서비스 시작
STEP 7 — JAR 빌드 및 서버 전송
JAR(Java ARchive)는 Spring Boot 프로젝트를 하나의 실행 가능한 파일로 압축한 것입니다.
서버에서는 이 JAR 파일 하나만 있으면 별도의 WAS(Tomcat 등) 없이 애플리케이션을 바로 실행할 수 있습니다.
./gradlew clean bootJar는 기존 빌드 결과물을 깨끗이 지우고(clean) 새로 JAR 파일을 만드는(bootJar) 명령입니다.
이 작업은 로컬 터미널에서 진행하면 됩니다.(필자는 로컬 IntelliJ 터미널에서 진행)
# JAR 빌드
./gradlew clean bootJar
# 결과물: build/libs/프로젝트명-0.0.1-SNAPSHOT.jar
빌드가 완료되면 scp로 JAR 파일을 서버로 전송합니다.
전송 후 앱 디렉터리로 이동시키고, chown으로 소유자를 서비스 전용 계정으로 변경합니다.
전용 계정으로 실행하면 서비스가 탈취되더라도 시스템 전체에 미치는 영향을 최소화할 수 있습니다.
scp -i "~/.ssh/[저장한 이름.pem]" \
"./build/libs/프로젝트명-0.0.1-SNAPSHOT.jar" \
ubuntu@[IP]:~/app.jar
# 서버에서 앱 디렉토리로 이동
sudo mv ~/app.jar /opt/[프로젝트명]/app.jar
sudo chown [프로젝트명]:[프로젝트명] /opt/[프로젝트명]/app.jar
STEP 8 — 서비스 시작 및 로그 확인
systemd는 Linux 서버에서 프로세스를 관리하는 시스템입니다.
Spring Boot 애플리케이션을 systemd에 서비스로 등록하면 서버가 재시작될 때 자동으로 애플리케이션도 함께 실행되고, systemctl 명령으로 손쉽게 시작·정지·상태 확인을 할 수 있습니다.
systemctl status로 정상 실행 여부를 확인하고, 오류가 발생했다면 journalctl로 상세 로그를 조회합니다.
journalctl은 systemd가 수집한 로그를 보는 명령어로, -n 50은 최근 50줄만 출력하라는 옵션입니다.
sudo systemctl start [프로젝트명]
sudo systemctl status [프로젝트명]
# 로그 확인
sudo journalctl -u [프로젝트명] -n 50 --no-pager
systemctl status 결과에서 Active: active (running)이 뜨면 서비스가 정상적으로 시작된 것입니다.
7 STEP 9 : Nginx 리버스 프록시 설정
Nginx는 고성능 웹 서버로, 여기서는 리버스 프록시 역할로 사용합니다.
리버스 프록시란 외부(인터넷)에서 들어오는 요청을 받아 내부 서버(Spring Boot, 포트 8080)로 대신 전달해 주는 중간 서버입니다.
Spring Boot를 포트 80으로 직접 노출하지 않아도 되어 보안 및 유연성이 높아집니다.
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/[프로젝트명]
설정 파일의 주요 옵션을 살펴보면, proxy_set_header는 Nginx가 Spring Boot로 요청을 전달할 때 원래 클라이언트의 IP·프로토콜 등 정보를 함께 넘겨주기 위한 설정입니다.
이 설정이 없으면 Spring Boot 입장에서 모든 요청이 localhost에서 온 것처럼 보입니다.
client_max_body_size는 파일 업로드 시 허용할 최대 크기로, 기본값(1MB)보다 크게 올려두지 않으면 파일 업로드가 실패합니다.
server {
listen 80;
server_name [Elastic IP 또는 도메인];
client_max_body_size 110M;
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;
}
location /uploads/ {
alias /var/project/uploads/;
}
}
Nginx는 sites-available에 설정 파일을 작성하고, sites-enabled에 심볼릭 링크(바로 가기)를 만들어 활성화하는 구조로 동작합니다.
nginx -t는 설정 파일에 문법 오류가 없는지 미리 검사하는 명령으로, 오류 없이 통과한 뒤 재시작해야 안전합니다.
sudo ln -s /etc/nginx/sites-available/[프로젝트명] /etc/nginx/sites-enabled/[프로젝트명]
sudo nginx -t
sudo systemctl restart nginx
적용 후 브라우저에서 http://[Elastic IP]로 접속해 서비스가 정상 동작하는지 확인합니다.
8 주의사항 및 재배포 방법
ddl-auto 설정 주의
ddl-auto는 Spring Boot가 실행될 때 데이터베이스 테이블을 어떻게 처리할지 결정하는 설정입니다.
운영 환경에서 잘못 설정하면 테이블이 삭제되거나 의도치 않게 변경될 수 있으므로 단계에 맞게 조정해야 합니다.
해당 설정을 배포 전에 확인하여 올바르게 수정하시길 바랍니다.
| 단계 | ddl-auto 값 | 설명 |
|---|---|---|
| 개발 중 | update | 엔티티 변경 시 테이블을 자동으로 생성하거나 수정해 줍니다. |
| 최초 배포 | update | 서버에 테이블이 아직 없으므로 처음엔 update로 자동 생성합니다. |
| 운영 안정화 후 | validate | 테이블과 엔티티가 일치하는지만 검사합니다. 실수로 스키마가 변경되는 사고를 방지합니다. |
재배포 절차
코드를 수정하고 서버에 반영할 때는 아래 3단계를 순서대로 진행합니다.
로컬에서 새 JAR을 빌드하고, 서버로 전송한 뒤, 기존 파일을 교체하고 서비스를 재시작하는 흐름입니다.
# 1. 로컬에서 빌드
./gradlew clean bootJar
# 2. WSL에서 서버로 전송
scp -i "~/.ssh/[저장한 이름.pem]" \
"./build/libs/앱.jar" \
ubuntu@[IP]:~/app.jar
# 3. 서버에서 교체 및 재시작
sudo mv ~/app.jar /opt/[프로젝트명]/app.jar
sudo chown [프로젝트명]:[프로젝트명] /opt/[프로젝트명]/app.jar
sudo systemctl restart [프로젝트명]
~/.ssh/ 경로에 보관하고 chmod 400 권한을 설정해야 합니다. GitHub 등 원격 저장소에 올리지 않도록 .gitignore에 등록하세요.
| 잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다. |

'인프라 & 배포 > AWS' 카테고리의 다른 글
| [AWS] AWS에 프로젝트 배포하기 (3) - 배포 간략화 (1) | 2026.06.19 |
|---|---|
| [AWS] AWS에 프로젝트 배포하기 (1) - EC2 생성, 초기 설정, 배포 준비 (0) | 2026.06.19 |
