[태그:] Docker

  • 한 평짜리 서버 — WordPress를 Docker로 띄우기

    한 평짜리 서버 — WordPress를 Docker로 띄우기

    한 평짜리 서버 — 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_EXTRA X-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.ymlminipc_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.