[태그:] 블로그

  • 왜 자기 컴퓨터에 블로그를 차렸나

    왜 자기 컴퓨터에 블로그를 차렸나

    왜 자기 컴퓨터에 블로그를 차렸나

    셀프호스팅 구축기 1편. 시리즈를 여는 글. 결정의 이유와 그때 따져본 것들.


    TL;DR

    • 티스토리·네이버 블로그도 좋은데 5가지가 거슬렸다: 광고, 톤 강제, 데이터 잠금, 폐쇄 위험, 실험 제한
    • 자기 컴퓨터(미니PC) + WordPress + 도메인으로 가면 위 5가지가 한 번에 풀린다
    • 초기 비용 = 도메인 갱신비 연 $10. 미니PC는 이미 있었다
    • 함정: “내가 다 책임진다” — 백업·보안·업데이트·다운타임 모두 본인 일

    1. 처음에는 티스토리부터 봤다

    블로그 만들기로 결정한 순간 자연스러운 첫 후보는 티스토리·네이버 블로그였다. 가입 5분, 글 쓰면 끝. 한국어 검색 노출도 좋고 모바일 앱도 있다.

    근데 사흘 정도 만들면서 5가지가 거슬렸다.

    거슬린 것 설명
    광고 글 위·아래·중간에 플랫폼 광고. 내 톤과 안 맞는 콘텐츠와 섞임
    톤 강제 플랫폼 디자인이 “친근한 일상” 톤. 객관적·기술적 글이 어색해짐
    데이터 잠금 내 글 데이터가 플랫폼 DB에 있음. 마크다운으로 추출 어려움
    폐쇄 위험 야후 블로그·다음 view처럼 서비스 종료되면 글 다 날아감
    실험 제한 새 플러그인·AI 친화 robots.txt·자체 분석 도구 못 붙임

    내가 쓸 글은 “공부·트레이딩·자동화” — 기술적이고 길고 차분한 톤. 카페·블로그 플랫폼과 잘 안 맞았다.


    2. 다른 선택지를 펼쳐보다

    자기 호스팅 외에 4가지 정도 후보가 있다.

    

    각각 거른 이유:

    • Medium/Substack: 영어권 + 구독 모델 + 톤 강제. 한국어 노출 약함
    • GitHub Pages + Hugo: 정적 사이트, 가장 가벼움. 단 댓글·분석·플러그인 다 외부 의존
    • Notion 공개 페이지: 검색엔진 노출 약함. AI 친화 robots.txt 못 박음

    3. 자기 호스팅 = 다섯 가지를 한 번에 푼다

    거슬렸던 것 자기 호스팅에서
    광고 0개. 내가 안 박으면 안 뜸
    톤 강제 테마·CSS 직접 통제. 사장님 톤 그대로
    데이터 잠금 DB 내 컴퓨터에 있음. 매일 백업 자동
    폐쇄 위험 내 컴퓨터가 죽지 않는 한 유지
    실험 제한 mu-plugin·robots.txt·llms.txt·트래커 자유

    그리고 한 가지 추가 이점: AI 검색 시대(GEO)에 영문판을 자동 생성해서 글로벌 노출까지 가능. 플랫폼 블로그는 다국어 자체가 어려움.


    4. 비용 비교

    항목 티스토리·네이버 자기 호스팅 (별고래)
    가입비 0원 도메인 갱신비 연 $10 (≈14,000원)
    호스팅 무료 (광고 포함) 미니PC 전기료 (이미 켜져 있음)
    광고 수익 절반 플랫폼 가져감 100% 본인 (광고 안 박을 거라 무관)
    백업 플랫폼이 함 (단 추출 어려움) 본인 책임 (cron으로 자동화)
    유지비 0원 0원 (도메인 외)

    미니PC가 없는 사람은 라즈베리파이($35) 또는 중고 미니PC($100~200) + 도메인. 그래도 1년 총비용 $50 미만.


    5. 함정 — “내가 다 책임진다”

    자기 호스팅의 진짜 가격은 돈이 아니라 책임.

    책임 빈도 자동화 가능?
    DB 백업 매일 ✅ cron + Obsidian Vault로 자동
    보안 업데이트 주 1회 △ wp-cli + 알림
    SSL 갱신 매 90일 ✅ Cloudflare Tunnel이 알아서
    공격 대응 24/7 ✅ WAF + Wordfence
    다운타임 (정전·인터넷) 가끔 ❌ 본인이 처리
    사이트 디자인·플러그인 충돌 가끔 ❌ 본인이 디버깅

    플랫폼 블로그가 대신 해주던 5가지가 다 내 일이 된다. 자동화 가능한 건 자동화하고, 나머지는 받아들인다.


    FAQ

    Q. 미니PC 없으면 클라우드 VPS로 가도 되나?
    가능. AWS Lightsail·DigitalOcean·Vultr 등 월 $5짜리 VPS면 충분. 단 매월 비용 발생 + 미니PC만큼의 통제 자유 제한.

    Q. 트래픽 폭주하면 우리집 인터넷 마비 안 되나?
    Cloudflare Tunnel + CDN을 앞에 두면 정적 콘텐츠는 Cloudflare가 흡수. 우리집 미니PC까지 가는 동적 요청만 처리. 보통 viral 터져도 견딤.

    Q. 글 쓸 때마다 PC 켜야 하나?
    WordPress 관리 화면 = /starport 로그인. 어디서든 가능. 글 쓰는 PC와 미니PC는 별개. 미니PC만 24/7 켜져 있으면 됨.

    Q. 외국인이 한국어 글을 읽을 수 있나?
    9편(Polylang)에서 다룬다. 옵시디언에서 한국어 1개만 쓰면 LLM이 영문판 자동 생성 + Polylang으로 hreflang 처리. 사장님 부담 = 한국어 1개.

    Q. 후회 안 했나?
    하루 정도 후회했다 — 첫 셋업할 때 Apache 설정·SSL 갱신·DB 권한 문제로 새벽 3시까지 헤맸다. 끝나고 나면 안 한다. 같은 일을 두 번 안 한다.


    다음 편 예고

    2편 — 한 평짜리 서버: WordPress를 Docker로 띄우기. 미니PC 한 대에 WordPress + MariaDB + Redis를 Docker Compose로 30분에 가동한 과정.


    한 줄 정리

    플랫폼 블로그는 시작이 쉽지만 광고·톤·데이터 잠금 5가지가 거슬린다. 자기 호스팅은 처음 셋업 하루 + 매일 자동화 + 책임 받아들이기 = 다섯 가지를 한 번에 푼다. 비용 연 $10.

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