한 평짜리 서버 — WordPress를 Docker로 띄우기
셀프호스팅 구축기 2편. 인프라 골격 30분.
TL;DR
- WordPress + MariaDB + Redis 세 컨테이너를
docker-compose.yml한 파일로 - 호스트 포트
127.0.0.1:8090만 노출. 외부는 Cloudflare Tunnel(9편)이 라우팅 - Redis는 Object Cache로 DB 쿼리 캐싱. 무료 + 페이지 응답 30% 빨라짐
- 함정 5개: 한글 파일명 SCP·healthcheck
--connect·named volume 비밀번호 잔류·WP_REDIS_HOST=redis·WORDPRESS_CONFIG_EXTRAX-Forwarded-Proto
1. 왜 Docker인가 — 호스트 직접 설치 vs 컨테이너
| 비교 | 호스트 직접 (apt install) | Docker Compose ⭐ |
|---|---|---|
| 설치 단순함 | apt install apache2 php mariadb-server 등 |
docker compose up -d |
| 의존성 충돌 | PHP 8.1 vs 8.3 같은 갈등 발생 | 컨테이너 격리 |
| 미니PC OS 재설치 시 | 처음부터 다시 | compose.yml + 데이터 백업이면 끝 |
| 업데이트 | 시스템 패키지 매니저 (까다로움) | docker compose pull && up -d |
| 다른 컨테이너 (WP·Umami·cloudflared) 공존 | 어려움 | 자연스러움 |
미니PC가 이미 다른 서비스를 Docker로 돌리고 있다면 답은 Docker.
2. 구조 한 장
세 컨테이너가 같은 docker network 안에서 호스트네임(db, redis)으로 통신. 외부 노출은 호스트 127.0.0.1:8090만.
3. docker-compose.yml 핵심
services:
wordpress:
image: wordpress:php8.3-apache
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: wp
WORDPRESS_CONFIG_EXTRA: |
if (!empty($$_SERVER['HTTP_X_FORWARDED_PROTO']) && $$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$$_SERVER['HTTPS'] = 'on';
}
volumes:
- wordpress_data:/var/www/html
ports:
- "127.0.0.1:8090:80"
db:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_DATABASE: wp
MARIADB_USER: wp
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- wordpress_db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect"]
interval: 10s
timeout: 5s
retries: 6
start_period: 30s
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- wordpress_redis_data:/data
volumes:
wordpress_data:
wordpress_db_data:
wordpress_redis_data:
.env 분리:
DB_PASSWORD=<openssl rand -hex 24>
DB_ROOT_PASSWORD=<openssl rand -hex 24>
chmod 600 .env. git에 절대 X.
4. 가동 + 검증
cd /home/user/wordpress
docker compose up -d
docker compose ps
curl -I http://localhost:8090
응답이 HTTP/1.1 302 (WordPress가 초기 설치 페이지로 리디렉트) 면 성공.
브라우저로 http://localhost:8090 접속 → 5분 위자드 → 관리자 계정 생성 (이름은 admin 말고 본인 단어. brute force 1차 회피).
5. Redis Object Cache 활성
플러그인 redis-cache 설치 후:
wp config set WP_REDIS_HOST redis --allow-root
wp config set WP_REDIS_PORT 6379 --allow-root
wp config set WP_REDIS_PREFIX byeolgorae: --allow-root
wp config set WP_CACHE true --raw --allow-root
wp redis enable --allow-root
WP_REDIS_HOST=redis 이게 핵심. Docker 호스트네임. 127.0.0.1이면 자기 컨테이너 안만 봐서 실패.
6. 함정 — 우리가 실제로 만난 것
함정 1. 한글·박스 문자 파일 SCP
docker-compose.yml을 minipc_write_file로 작성하다가 한글 주석 + 특수문자 조합에서 SSH escape 깨짐 (bash: -c: 줄 1: '...' 찾는 도중 예상치 못한 파일의 끝).
→ Windows에서 c:\tmp\에 평문 작성 → scp → 미니PC /tmp/ → sudo cp 경로로 우회.
함정 2. mariadb healthcheck --innodb-initialized 미지원
웹 가이드 따라 ["CMD", "healthcheck.sh", "--connect", "--innodb-initialized"] 박았더니 unknown option 에러.
→ --connect 만 사용 + start_period: 30s 길게.
함정 3. .env 비밀번호 바꾼 후 “Database Error”
DB 비밀번호 한 번 바꾸고 docker compose up -d 했더니 500. 이유: named volume에 옛날 비밀번호가 저장된 MariaDB DB 파일이 살아있음. 새 비밀번호로는 인증 실패.
→ docker compose down -v (-v가 volume 같이 제거) → 다시 up -d. 운영 데이터 있으면 절대 안 됨, 초기 셋업 단계에서만.
함정 4. Redis Connection refused 127.0.0.1:6379
WP_REDIS_HOST=127.0.0.1 박았다가 컨테이너 안에서 자기 자신 보는 꼴. Redis는 다른 컨테이너.
→ WP_REDIS_HOST=redis (Docker network 호스트네임).
함정 5. HTTPS 리버스 프록시 무한 리다이렉트
Cloudflare Tunnel이 앞에 서서 HTTPS 종단 후 미니PC엔 HTTP로 forward. WordPress가 자기를 HTTP로 인식 → “HTTPS로 가야 함” 리다이렉트 → 무한 루프.
→ WORDPRESS_CONFIG_EXTRA에 X-Forwarded-Proto 처리 (위 yml 참고).
FAQ
Q. 메모리 얼마나 쓰나?
WP(php-fpm 또는 apache) ~200MB, MariaDB ~150MB, Redis ~30MB. 합 ~400MB. 미니PC 8GB RAM이면 여유 충분.
Q. 디스크 용량은?
이미지 합 ~1GB. DB는 콘텐츠에 따라 (글 100편 + 이미지 = ~500MB).
Q. PHP 8.3 말고 8.2면 안 되나?
WordPress 6.x는 8.2·8.3 둘 다 지원. 8.3이 더 빠름 (JIT 안정화). 최신 권장.
Q. mariadb 말고 mysql 쓰면?
mariadb는 mysql 호환 + 라이센스 자유 + Oracle 의존 X. 둘 다 작동. 1인 운영엔 mariadb 추천.
Q. 백업은 어떻게?
4편(백업·캐시·이미지)에서 자세히. 매일 03:00 cron으로 mariadb-dump → gzip → Obsidian Vault.
다음 편 예고
3편 — AI도 읽으라고: robots.txt와 llms.txt. 봇 차별 대신 AI 크롤러 14종 명시 허용. GEO 시대 콘텐츠 노출 전략.
한 줄 정리
WordPress·MariaDB·Redis 세 컨테이너를 docker-compose.yml 한 파일로 묶어 30분에 가동. 호스트 127.0.0.1:8090만 노출, 외부 라우팅은 Cloudflare Tunnel에 위임. 함정은 한글 SCP·healthcheck·volume 잔류·Redis host·X-Forwarded-Proto.

답글 남기기