도커로 개인 블로그 서버 구축 계획 세우신 거 축하드립니다.
이거 정말 제대로 배우실 수 있는 좋은 프로젝트예요.
단순히 '설치'하는 것을 넘어, '서비스를 운영'하는 전 과정을 경험해보는 거라 실무 경험치가 확 오를 거예요.
질문 주신 내용이 전형적인 '이론은 아는데 실제 구현이 막막한' 단계라서, 제가 제가 겪었던 시행착오랑, 실제 운영 환경에서 가장 중요하다고 느끼는 로드맵 순서대로 좀 자세하게 정리해 드릴게요.
결론부터 말씀드리자면, docker-compose 사용을 강력하게 추천합니다.
개별 서비스 단위로 docker run을 반복해서 돌리는 건, 서비스가 2~3개만 돌릴 때는 괜찮지만, 블로그 서버처럼 DB, 웹 앱, 캐시(Redis 등)가 엮이기 시작하면, 이 의존성 관리가 개판이 됩니다.
docker-compose는 이 모든 서비스들을 한 파일에서 '하나의 시스템'처럼 묶어주고, 네트워크 연결까지 한 번에 정의해주기 때문에, 나중에 서버를 옮기거나 설정을 수정할 때의 안정성이 비교 불가 수준이에요.
--- ###
1단계: 아키텍처 설계 및 스택 결정 (가장 중요) 기술 스택을 정하는 게 제일 먼저예요.
'무엇을 돌릴지'가 전체 구조를 결정합니다.
1.
블로그 종류 결정: * CMS 기반 (예: WordPress, Ghost): 가장 일반적이고 빠릅니다.
백엔드(PHP 등)와 DB(MySQL/MariaDB)가 필요해요.
이 경우, 최소 3개의 서비스가 필요합니다.
(웹 서버, 앱 서버, DB 서버) * 정적 사이트 생성기 (예: Jekyll, Hugo): 블로그 글을 Markdown으로 쓰고, 빌드 과정을 거쳐 정적인 HTML 파일로 만듭니다.
(가장 가볍고 빠름).
이 경우, 빌드 과정만 컨테이너화하고, 실제 서비스는 Nginx가 서빙하는 구조가 됩니다.
- 개인 개발용 (예: Django/Flask): 직접 코딩해서 API 형태로 운영하는 경우.
네트워크 설계: * 모든 서비스는 하나의 가상 네트워크 안에 묶여야 합니다.
(이게 docker-compose.yml 파일에서 networks: 섹션으로 정의됩니다.) * 각 서비스는 서로 서비스 이름으로 통신합니다.
(예: 웹 앱이 DB에 접속할 때 localhost:3306이 아니라 db_service_name:3306으로 접근합니다.)
실무 팁: 초보 단계라면, **CMS 기반 (예: WordPress + MySQL)**으로 가시고, 이 구조를 docker-compose로 묶는 연습부터 하시는 걸 추천합니다.
이 구조가 가장 많은 컴포넌트(웹, DB, 캐시)를 포함하고 있어서 학습 곡선이 높지만, 그만큼 배울 것이 많습니다.
--- ###
️ 2단계: 로컬 개발 환경 구축 (Docker Compose의 힘) 이제 docker-compose.yml 파일을 중심으로 모든 것을 정의합니다.
1.
볼륨(Volume) 정의 (
️
️
️
️
️ 최고 중요): * 이게 제일 많이 놓치는 부분이에요.
컨테이너는 기본적으로 '휘발성 메모리'에 데이터를 저장합니다.
컨테이너가 멈추거나 삭제되면 그 안의 모든 데이터는 사라집니다.
- **DB 데이터, 블로그 파일(업로드된 이미지 등)**은 반드시 호스트 머신의 디렉토리나 Docker Volume에 저장되도록 정의해야 합니다.
volumes: 설정을 통해 이 영속성을 확보하는 게 이 단계의 핵심입니다.
서비스 정의 및 의존성 설정: * docker-compose.yml에 db, app, nginx 세 개의 서비스를 정의합니다.
depends_on: 키워드를 사용해서, app 서비스가 시작되기 전에 db 서비스가 먼저 준비되도록 순서를 강제합니다.
Nginx (리버스 프록시) 설정: * Nginx는 외부의 모든 요청을 받는 '문지기' 역할을 합니다.
- 외부에서 접속하는 포트(예: 80, 443)는 Nginx 컨테이너가 독점합니다.
- Nginx의 역할은 "외부에서 들어온 요청이 블로그라면
app_service:port로 보내고, API 요청이라면 api_service:port로 보내라"라고 내부 트래픽을 분기(Routing)해주는 겁니다.
- 이 설정 파일(
nginx.conf)을 Nginx 컨테이너가 접근할 수 있는 볼륨에 마운트해주면 됩니다.
--- ###
3단계: 외부 접근성 확보 (실제 배포 시점) 이제 로컬 컴퓨터에서 돌아가는 걸, 인터넷에 띄우는 과정입니다.
도메인 연결 및 DNS 설정: * 가장 먼저 도메인 구매 후, 도메인 관리 페이지에서 A 레코드를 서버의 공인 IP 주소로 연결해야 합니다.
2.
포트 포워딩 및 보안 그룹 설정 (가장 헷갈리는 부분): * 클라우드 환경(AWS EC2, GCP VM 등)을 사용한다면, 서버 OS의 방화벽 설정 외에, 클라우드 플랫폼 레벨의 보안 그룹(Security Group) 설정을 반드시 확인해야 합니다.
- 외부에서 80(HTTP)과 443(HTTPS) 포트로 접속할 수 있도록 인바운드 규칙을 열어줘야 합니다.
이게 안 되어 있으면, 내부적으로는 완벽해도 외부에서는 접속이 안 됩니다.
- 포트 포워딩 자체는 보통 클라우드 VM의 인바운드 규칙으로 처리됩니다.
SSL/TLS 적용 (Let's Encrypt/Certbot): * 무조건 HTTPS로 가야 합니다.
- 여기서 트릭이 있어요.
certbot 컨테이너를 별도로 띄우고, 이 컨테이너가 Nginx가 서빙하는 80 포트를 잠깐 점유해서 인증서를 발급받도록 하는 과정이 필요합니다.
- 이 과정을 자동화하려면, Nginx 설정을 수정하여 SSL 키를 불러오게 만들고,
cron이나 별도의 스케줄링 컨테이너를 통해 갱신 주기를 관리해야 합니다.
--- ###
️ 자주 걸리는 초기 설정 함정 및 체크리스트 이건 제가 몇 번씩 겪었던 실수들입니다.
꼭 체크해보세요.
환경 변수(Environment Variables) 하드코딩: * 개발할 때 docker-compose.yml이나 .env 파일에 DB 비밀번호 같은 민감 정보를 직접 넣지 마세요.
- 실제 배포 시에는 AWS Secrets Manager나 HashiCorp Vault 같은 전용 시크릿 관리 시스템을 사용하거나, 최소한
.env 파일을 사용하고 Git에는 절대 커밋하지 않도록 .gitignore에 등록해야 합니다.
네트워크 오해: * docker-compose를 쓰면 모든 서비스가 같은 가상 네트워크에 있기 때문에, 컨테이너 A에서 컨테이너 B로 요청할 때 http://localhost:80을 쓰면 안 됩니다. 반드시 http://[서비스이름]:[포트]을 써야 합니다.
3.
권한 문제 (Linux/OS 레벨): * 컨테이너 내부의 웹 서버 프로세스가 파일을 저장하거나 접근할 때, 호스트 OS의 특정 사용자/그룹 권한 문제로 실패하는 경우가 있습니다.
- 특히 파일 업로드 폴더 같은 곳은
user:group 권한을 명시적으로 맞춰주거나, runuser 같은 도구를 사용해 권한을 맞춰주는 과정이 필요할 수 있습니다.
--- ###
최종 정리 로드맵 (가장 효율적인 순서) 1.
[Phase 1] 뼈대 잡기: docker-compose.yml 작성 (서비스 3~4개 정의).
[Phase 2] 데이터 영속화: 모든 데이터 볼륨 정의 및 테스트.
(DB에 데이터 넣고, 컨테이너 껐다 켜서도 데이터가 남아있는지 확인).
3.
[Phase 3] 외부 노출 준비: Nginx 설정 파일 작성 및 docker-compose에 마운트.
4.
[Phase 4] 테스트: 로컬에서 외부 IP처럼 접근하는 시뮬레이션 수행.
(로컬 포트 포워딩 테스트).
5.
[Phase 5] 클라우드 배포: 클라우드 VM 준비 -> 보안 그룹 열기 -> DNS 연결 -> Certbot 연동.
이 순서대로 진행하시면, 이론과 실습의 간극을 최소화하면서 가장 자연스럽게 최종 목표에 도달하실 수 있을 겁니다.
너무 완벽하게 하려고 하기보다, 일단 '돌게 만드는 것'에 집중하시고, 돌아가기 시작하면서 발생하는 오류들을 하나씩 해결해나가는 과정 자체가 최고의 학습입니다.
궁금한 거 있으면 언제든지 다시 질문 주세요!