제가 운영하며 직접 확인해 볼 수 있는 하나의 완전한 시스템
지금 보고 계신 사이트는 제가 직접 설정하고, 보안을 적용하고, 업데이트하고, 모니터링하는 서버에서 돌아갑니다. 빈 서버부터 이 페이지까지 전부요.
필요
포트폴리오는 역량을 나열하는 데서 그치지 않고 증명해야 합니다. 관리형 플랫폼에 올리면 제가 보여 주고 싶은 것, 즉 안정적이고 안전한 서비스를 오래 운영하는 능력이 오히려 가려집니다.
아이디어
호스팅 자체를 증거로 만드는 것입니다. 여기에 쓰인 모든 내용은 이 페이지를 제공하는 바로 그 서버에서 실시간으로 확인할 수 있습니다.
만든 것
- 파리 리전의 클라우드 서버. 그곳의 무료 자원이 부족해 며칠에 걸쳐 여섯 번 시도한 끝에 확보했습니다.
- 웹 스택 전체. 서비스마다 제한된 공간에서 따로 돌아가 한곳의 문제가 다른 곳으로 번지지 않습니다.
- 첫날 밤부터 보안 강화를 시작했습니다. 하룻밤에 7가지 조치를 서비스 중단 없이 적용했고, 이후 단계적으로 이어 갔습니다.
- 자동 업데이트: 승인된 변경 사항은 저절로 반영되고, 상태 점검을 거쳐, 새 버전이 응답하지 않으면 자동으로 이전 버전으로 돌아갑니다.
- 데이터베이스의 지속적인 백업과, 일·주·월 단위로 보관하는 야간 스냅숏.
- 사이트 보안을 매시간 점검하고 결과를 공개하는 별도의 프로브. 아래에서 확인할 수 있습니다.
결과
- 5별도의 점검 도구가 매시간 다시 실행하는 보안 점검
- 7하룻밤에 무중단 적용
- 6서버 확보까지 걸린 시도 횟수
- 1시간독립 보안 점검 주기
2026년 8월부터 EventMap과 함께 이 포트폴리오를 제공하고 있습니다. 아래의 실시간 점검 결과는 사람이 쓴 것이 아니라 별도의 프로브가 측정한 것입니다.
직접 확인해 보세요
실시간 점검
- TLS 확인됨
- 오리진 확인됨
- 헤더 확인됨
- DNSSEC 확인됨
- 가용성 확인됨
화면으로 보기
배운 점
서버 안에서만 테스트해서는 안 됩니다. 방화벽이 두 겹이면, 서비스가 로컬에서는 완벽하게 응답해도 인터넷에서는 아무도 접속하지 못할 수 있습니다. 그리고 무언가를 설치하지 않기로 하는 판단(여기서는 데이터베이스 서버)도 운영 역량입니다.
기술 세부 정보 기술 스택, 아키텍처, 설계 결정 — 기술 담당자용
기술 스택
- Ubuntu 22.04
- Oracle Cloud ARM (Always Free)
- nginx
- Node.js + Express
- SQLite (node:sqlite)
- systemd
- fail2ban
- iptables
- Cloudflare
- GitHub Actions
- Litestream + restic
한눈에 보는 아키텍처
- 방문자의 브라우저
- Cloudflare — TLS 및 캐시
- nginx — 보안 헤더, 요청 속도 제한
- Node.js + Express — 서버에서 렌더링하는 페이지, 7개 언어 지원, 샌드박스로 격리된 systemd 서비스
- SQLite (node:sqlite) — 프로젝트 데이터와 자체 수집 방문 기록
- 주변 구성: GitHub Actions가 모든 변경 사항을 테스트하고, VM은 검증된 릴리스를 가져와 /health를 확인한 뒤 실패하면 롤백합니다. 보안 옵저버토리는 30분마다 보안을 다시 점검합니다.
작동 방식
- 4 OCPU / 24GB VM(Ubuntu 22.04). 격리된 서비스 앞에 nginx 리버스 프록시를 두고, 각 서비스는 셸이 없는 전용 시스템 사용자로 ProtectSystem=strict와 NoNewPrivileges를 적용해 실행합니다.
- 첫날 밤(2026년 8월 23일): 관리자 비밀번호 재생성, SSH에 fail2ban, 엄격한 보안 헤더(CSP, HSTS, X-Frame-Options), 접근 로그의 IP 마지막 옥텟 0 처리, journald 보존 기간 제한, nginx 로그 순환, 비밀 정보의 암호화 백업을 VM 밖에 보관.
- 이후: nginx 요청 속도 제한, rpcbind 비활성화, 스왑, 원격 데스크톱을 127.0.0.1에만 바인딩(SSH 터널 전용), SSH 비밀번호 인증 비활성화, Full (strict) 모드의 Cloudflare Origin CA 인증서.
- 풀(pull) 방식 지속 배포: master에 push하면 GitHub Actions가 검증하고 prod 태그를 옮깁니다. VM은 systemd 타이머로 이를 가져와 상태를 점검하고, 문제가 있으면 자동으로 롤백합니다. 열린 인바운드 포트도, GitHub에 저장된 VM 자격 증명도 없습니다.
- 두 겹의 방화벽(VM의 iptables + 클라우드 Security List). 서버 안에서만 테스트하지 않는 이유입니다.
- 의도한 절충: 보안 업데이트는 자동으로 설치되지만, VM이 스스로 재부팅하거나 메이저 버전을 바꾸는 일은 없습니다.
- 방문 기록은 자체 수집만 합니다. 제3자 쿠키는 없고, IP 주소는 저장 전에 해시 처리하며, 기록은 12개월 후 삭제합니다.
설계 결정과 절충
- 브라우저에서 불러오는 대신 서버에서 렌더링하는 페이지: 7개 언어 모두 검색 엔진에 색인되고, JavaScript 없이도 읽을 수 있습니다.
- Docker 대신 systemd 서비스: 운영 환경은 CPU·메모리 할당량을 둔 격리된 systemd 유닛으로 돌아갑니다. 실제로 배포하지 않는 컨테이너는 아무것도 증명하지 못합니다.
- 두 번째 API를 만드는 대신 공개 JSON 피드 하나(/api/contenus.json)를 Mindmap이 재사용합니다. 진실 공급원이 하나뿐이라 동기화할 것이 없습니다.
발생한 문제와 해결
- 사이트 개편 후, pull request 자동 보고서가 내장 스크린숏 때문에 GitHub 댓글 한도인 65,536자를 넘었습니다. 테스트는 통과했지만 게시는 실패했습니다. 썸네일을 가볍게 하고 분량을 60,000자 이내로 제한해 해결했습니다.
- 배포 후에도 Cloudflare가 최대 4시간 동안 옛 스크립트를 계속 제공했습니다. 이제 모든 CSS·JavaScript URL에 콘텐츠 지문(?v=)을 붙여, 새 버전이 옛 파일과 섞이는 일이 없습니다.
- 아랍어 페이지에서 ‘43 → 9.9 MB’ 같은 값이 양방향 텍스트 알고리즘 때문에 거꾸로 표시되었습니다. 이제 라틴 문자 값은 Unicode 제어 문자로 격리합니다.
아직 부족한 점
- 자동 재부팅 없음 — 의도한 선택