2020년부터 티스토리(axgo.tistory.com)에 개발하면서 겪은 일을 적어 왔다. 구글 애드센스 승인도 그 주소로 받았다. 그런데 2023년 여름부터 글을 올릴 마음이 줄기 시작했다. 내 글 맨 위 광고 자리를(명당을…) 티스토리가 가져갔기 때문이다.
워드프레스로 옮기면 그만이지만, 그러려면 매달 서버비가 나간다. 그래서 서버를 무료로 준다는 오라클 클라우드에 가입하려고 했는데 번번이 막혔다. 그사이 티스토리에는 2023년 11월 이후 글이 두 편밖에 올라가지 않았다.

이 글은 오라클클라우드(OCI) 가입 문제가 풀린 뒤, 돈을 들이지 않고 블로그 플랫폼을 굴리려고 무엇을 조사했는지, 처음 블로그 시스템 구조가 어떤 모습이었는지, 그 구조가 어떻게 무료에 가깝게 구축했는지 정리한 기록이다. 지금 이 글이 올라가 있는 axgo.byitx.com 이 그 결과물이다.
목차
- 티스토리가 본문 상단 광고 자리를 가져갔다
- 워드프레스로 옮기면 매달 서버비가 나간다
- 2년 넘게 넘지 못한 오라클 가입
- 무료로 쓸 수 있는 것부터 하나씩 확인했다
- 오라클 A1 무료 한도는 공식 문서로 다시 확인했다
- 7일 동안 놀고 있으면 회수될 수 있다
- 오라클 무료 목록에서 쓸 것만 골랐다
- Cloudflare 는 시스템 아키텍처의 앞단부터 백업 저장소까지 맡는다
- 처음 그린 아키텍처
- 서버비 0원으로 외부 공격 표면을 최소화
- 포트를 열지 않고 공개하는 Cloudflare Tunnel
- 2 OCPU, 12 GB 한 대에 컨테이너를 모두 올린다
- 백업은 R2에, 코드는 GitHub 에
- OCI 가입을 넘어, 다음 통곡의 벽은 A1 용량이었다
- 처음 그림에서 바뀐 것들
티스토리가 본문 상단 광고 자리를 가져갔다
2023년 5월 31일, 카카오는 6월부터 티스토리 글 본문에 티스토리가 직접 붙이는 광고를 넣겠다고 발표했다(파이낸셜뉴스). 광고는 본문 상단이나 하단 중 한 곳에 붙고, 그 수익은 서비스 운영에 쓴다고 했다. 블로거가 직접 단 광고는 그대로 둔다는 설명도 붙었다.
6월 1일 시작하고 보니 그 광고는 모두 구글 애드센스였고, 대부분 본문 상단에 붙었다(머니투데이, 2023년 6월 30일). 블로거가 단 애드센스와 같은 자리를 두고 경쟁하게 된 셈이다. 같은 기사에는 하루 70달러이던 수익이 40달러로 줄었다는 어느 블로거의 말도 실렸다.
애드센스를 달아 본 사람은 안다. 제목 바로 아래, 본문이 시작되는 자리가 가장 잘 팔리는 자리다. 그 자리를 플랫폼이 가져갔고, 거기서 나오는 수익도 플랫폼 몫이 됐다. 내가 고를 수 있는 건 남은 자리 중 어디에 광고를 둘지 정도였다.
해법은 단순했다. 내 도메인에 내 블로그를 만들면 된다. 워드프레스라면 광고 위치도 테마도 마음대로 정할 수 있다. 도메인은 이미 10년치를 사 둔 상태였다. 남은 문제는 서버비였다.
워드프레스로 옮기면 매달 서버비가 나간다
먼저 Perplexity 에 “워드프레스 서버를 운영하는 가장 비용 효율적인 클라우드 서비스” 를 물었다. 조사 당시 받은 답을 정리하면 아래와 같다. 값은 요금제와 환율에 따라 달라지니 대략의 감으로만 보면 된다.
| 선택지 | 월 비용(대략) | 조사 당시 메모 |
|---|---|---|
| 국내 웹호스팅(Cafe24 등) | 11,000원부터 | 공유 호스팅. 결제와 지원은 편하지만 사양에 비해 비싸다 |
| AWS Lightsail(서울) | 5~7달러 | 메모리 0.5~1 GB |
| Vultr(서울) | 5~6달러 | 1 vCPU, 메모리 1 GB |
| Hetzner | 4유로 안팎 | 2 vCPU, 메모리 4 GB. 한국 리전이 없다 |
| Cloudways(관리형) | 14~16달러 | 서버 관리를 대신해 주는 비용이 붙는다 |
| Oracle Cloud Always Free | 0원 | Arm 기반 A1. 서버 관리는 직접 해야 한다 |
유료로 가면 월 5달러 안팎이 가장 싼 선인데, 그 값에 메모리가 1 GB 남짓이다. 나는 처음부터 워드프레스 옆에 n8n 을 올려 글 발행을 자동화할 생각이었다. 워드프레스용 MariaDB, n8n 용 PostgreSQL, 캐시용 Redis 까지 한 서버에 올리려면 1 GB 로는 모자라고, 메모리를 늘릴수록 월 비용도 같이 오른다.
그래서 답은 하나로 모였다. 오라클 클라우드의 Always Free 다. Arm 기반 A1 인스턴스를 기간 제한 없이 무료로 준다. 신용카드 확인을 거쳐 가입하기만 하면 된다. 하지만… 그 ‘가입하기만 하면‘ 이 문제였다.
2년 넘게 넘지 못한 오라클 가입
나는 오라클 클라우드 가입을 ‘통곡의 벽’ 이라고 불렀다. 가입 실패는 흔한 일이라 검색하면 같은 하소연이 줄줄이 나온다. 아래는 내 메일함에 남은 흔적이다.

② 오라클 고객지원에도 두 번 문의했다(2023년 2월, 2024년 8월)
③ 2023년 2월부터 2026년 8월까지 시도가 이어졌다
④ 가입한 뒤 받은 OCI 알림. 미리보기에 있던 이름은 가렸다
인증 메일은 가입을 시작할 때마다 온다. 화면에 보이는 것만 서른 통이 넘는데, 그만큼 가입을 시작했다가 끝내 계정을 만들지 못했다는 뜻이다.
가입 실패 대처법도 찾아봤다. 흔히 도는 처방은 이렇다.
- VPN 과 프록시를 끄고 집이나 휴대폰 네트워크에서 시도한다
- 시크릿 창에서 브라우저 확장 프로그램을 끄고 시도한다
- 카드 명의와 주소를 카드사에 등록된 것과 한 글자도 다르지 않게 넣는다
- 실패하면 24시간 기다렸다가 다른 네트워크나 다른 카드로 다시 한다
- 이미 오라클에 등록된 적이 있는 이메일은 다시 쓸 수 없다
- 그래도 안 되면 영업팀에 사용한 만큼 내는 유료 계정(Pay As You Go)을 요청한다
그러다 별생각 없이 평소 쓰던 메일 대신 두 번째 메일 주소로 가입을 해 봤다. 결과는…
한 번에 통과했다!! 2년 넘게 넘지 못하던 통곡의벽이 그렇게 싱겁게 열린 것이다.

왜 됐는지는 지금도 정확히 모른다. 같은 메일 주소로 실패가 쌓인 게 문제였을 수도 있고, 그날 운이 좋았을 수도 있다. 같은 메일로 계속 막히고 있다면 다른 메일 주소로 한 번 해 볼 만하다.
- 남들 다 하는 카드 영문주소, 등등등 항상 같은 방식이었지만,
- 한번도 사용하지 않았던 메일로 회원가입을 시도 했고
- 리전은 항상 시도 했던 Osaka 리전으로 생성했다.
무료로 쓸 수 있는 것부터 하나씩 확인했다
계정이 생기고 나서 본격적으로 조사를 시작했다. 질문은 “오라클 Always Free 와 Cloudflare 무료 요금제만으로, 애드센스 수익이 가능한 워드프레스 블로그를 운영할 수 있을까” 였고, 조건을 몇 가지 붙였다.
- 도메인은 10년치를 미리 사 뒀다
- 워드프레스와 함께 n8n 을 올려 무료 LLM API 로 글 발행을 자동화한다
- 서버가 날아가도 워드프레스와 n8n 을 빨리 되살릴 수 있어야 한다. GitHub 비공개 저장소와 Cloudflare R2 를 쓴다
- Terraform, Ansible 같은 IaC 로 관리하는 게 나은지도 따져 본다
오라클 A1 무료 한도는 공식 문서로 다시 확인했다
처음 받은 답에는 “Ampere A1 을 4 OCPU / 24 GB 까지 무료” 라고 적혀 있었다. 블로그 글에도 이 숫자가 아직 많이 남아 있다. 그런데 오라클 공식 문서(Always Free Resources)를 열어 보니 달랐다. 지금 기준은 한 달 1,500 OCPU 시간과 9,000 GB 시간이고, 한 달 내내 켜 두면 2 OCPU / 12 GB 다. 그 문서를 근거로 다시 물으니 AI 도 예전 기준을 옮긴 것이라고 인정했다. 무료 한도처럼 자주 바뀌는 숫자는 꼭 원문으로 확인해야 한다.

② 한 달 내내 켜 두면 2 OCPU, 메모리 12 GB 에 해당한다 ③ 춘천(South Korea North) 리전에서는 A1 을 만들 수 없다
③ 은 가입할 때 이미 겪은 일이다. 홈 리전을 고르는 목록에 서울도 춘천도 보이지 않았다. 춘천이 보였더라도 소용없었다. A1 무료 인스턴스를 만들 수 없는 리전이기 때문이다. 무료 자원은 홈 리전에만 만들 수 있고 홈 리전은 나중에 바꿀 수 없어서, 한국에서 가까운 일본 오사카(ap-osaka-1)를 골랐다.
7일 동안 놀고 있으면 회수될 수 있다

방문자가 적은 개인 블로그는 이 조건에 걸리기 쉽다. 그래서 크론으로 일부러 부하를 만드는 요령도 인터넷에 떠돈다. 나는 회수를 막는 쪽보다, 회수되거나 망가져도 빠르게 다시 만들수 있는 쪽을 택했다. 코드와 설정은 GitHub 에, 데이터 백업은 오라클 밖에 있는 Cloudflare R2 저장소에 둔다. 이 결정이 뒤에 나올 아키텍처의 모양을 정했다.
오라클 무료 목록에서 쓸 것만 골랐다
| 자원 | 무료 범위 | 블로그에서 맡을 일 |
|---|---|---|
| A1.Flex 인스턴스(Arm) | 2 OCPU, 메모리 12 GB | 워드프레스, DB, n8n 을 한 대에 |
| 블록 볼륨 | 부트 볼륨 포함 200 GB, 볼륨 백업 5개 | 부트 볼륨 하나 |
| 아웃바운드 전송 | 매달 10 TB | Cloudflare 캐시가 앞에서 받아 준 만큼 줄어든다 |
| Bastion | 무료(유료 계정도 무료) | 관리자 SSH 의 유일한 입구 |
목록에는 Object Storage 20 GB 나 매달 3,000통의 이메일 발송도 있지만 이번 구성에는 넣지 않았다. 백업은 오라클이 통째로 사라져도 남도록 다른 회사에 두기로 했기 때문이다.
Cloudflare 는 시스템 아키텍처의 앞단부터 백업 저장소까지 맡는다
도메인 네임서버를 Cloudflare 로 옮기면 무료 요금제만으로 DNS, CDN, DDoS 방어, TLS 인증서를 쓸 수 있다. 방문자는 Cloudflare 까지만 오고, 캐시에 있는 페이지는 서버까지 오지도 않는다.
백업 저장소로는 Cloudflare R2 를 골랐다. S3 호환 오브젝트 스토리지인데 매달 10 GB 까지 무료이고, 인터넷으로 내보내는 트래픽(egress)에 과금이 없다. 백업은 결국 복구할 때 내려받으려고 쌓아 두는 것이라 egress 트래픽이 제한 없이 무료라는 점이 가장 크게 작용했다. OCI는 Free egress 10TB 제약이 있지만 Cloudflare CDN 캐시가 OCI Free egress를 최소화 해주는 효과 또한 얻을 수 있게 된다.

마지막으로 GitHub 비공개 저장소는 무료다. Terraform, Docker Compose 파일, 스크립트, 운영 문서를 전부 여기에 둔다.
처음 그린 아키텍처
조사한 내용을 정리해 2026년 9월 6일 저장소에 처음 커밋한 아키텍처 그림이다. 화살표가 글자를 가로지르는 투박한 모양 그대로 가져왔다.

- Cloudflare Free: DNS, CDN, WAF 를 맡고 Tunnel 의 반대쪽 끝이 된다. 방문자는 여기까지만 온다.
- OCI Bastion: 관리자가 서버에 들어가는 유일한 입구다. 22번 포트로만, 그것도 Bastion 세션을 거쳐서 들어간다.
- OCI VCN: Public Subnet 하나에 인터넷 게이트웨이를 붙였다. 밖으로 나가는 연결은 자유롭지만 들어오는 문은 Bastion 에서 오는 22번 하나뿐이다. A1dml 80, 443 포트는 외부에 직접 노출하지 않을 계획이다.
- A1.Flex 인스턴스: Ubuntu 와 Docker Compose 위에 cloudflared, Caddy, 워드프레스 멀티사이트, MariaDB, Redis, PostgreSQL, n8n, 백업 컨테이너를 한 대에 모았다.
- Cloudflare R2: restic 으로 암호화한 백업이 쌓인다.
- GitHub 비공개 저장소: Terraform, Ansible, Compose 파일을 둔다. 서버는 여기서 코드를 받는다.
화살표 방향을 보면 이 구조의 요점이 보인다. 화살표는 ‘누가 먼저 연결을 여는가’ 를 뜻한다. Bastion 의 SSH 하나를 빼면 모든 화살표가 서버에서 바깥으로 나간다. 터널도, 백업도, 코드 받기도 서버가 먼저 연결을 연다. 바깥에서 서버로 먼저 들어오는 길은 Bastion 하나뿐이다.
서버비 0원으로 외부 공격 표면을 최소화
포트를 열지 않고 공개하는 Cloudflare Tunnel
처음 생각했던 구조는 일반적인 구성이었다. Cloudflare DNS 가 서버 공인 IP 를 가리키고, 서버는 80과 443 포트를 열고, Cloudflare 가 발급한 Origin 인증서를 웹 서버에 넣는다. 이 방식은 서버 IP 가 알려지면 Cloudflare 를 거치지 않고 서버로 바로 들어올 수 있다. 막으려면 방화벽에 Cloudflare IP 대역을 넣고, 대역이 바뀔 때마다 맞춰 줘야 한다.
Cloudflare Tunnel 은 근본적인 문제를 해결한다. 서버 안의 Docker Network을 이용하는 cloudflared 가 Cloudflare 쪽으로 먼저 연결을 맺고, 방문자 요청은 그 Private Tunnel 연결을 타고 들어온다. 서버는 들어오는 포트를 하나도 열 필요가 없고, TLS 인증서도 Cloudflare 가 처리한다. 그리고 결정적으로 Tunnel 을 무료로 사용할 수 있다!

실제로 그런지 맥북 터미널에서 확인해 보면 이렇다.

서버 쪽 방화벽은 Terraform 코드로 관리한다. 들어오는 규칙은 하나뿐이고 80, 443 포트 규칙은 아예 없다.

nginx:80 으로 넘긴다2 OCPU, 12 GB 한 대에 컨테이너를 모두 올린다
무료 A1 은 1CPU, 6GB 두 대로 나눌 수도 있지만 한 대에 몰았다. 컨테이너끼리 같은 네트워크 안에서 통신하니 구성이 단순하고, 메모리 여유도 한곳에 모인다. Bastion 으로 서버에 들어가 확인해 보면 이렇다.

메모리는 캐시를 빼면 3 GB(30% 가량) 가 안 되게 쓴다. 페이지는 nginx 캐시와 Cloudflare 엣지 캐시가 앞에서 받아 주는 만큼 PHP 까지 오는 요청이 줄어들어 WordPress의 부하를 최소화 해준다.
백업은 R2에, 코드는 GitHub 에
무료 인스턴스가 회수되거나 망가져도 빠른 복구가 가능해야 한다. 그래서 데이터베이스 덤프와 업로드 파일을 restic 으로 암호화해 하루 네 번 R2 에 올리고, 서버 설정과 코드는 전부 GitHub 저장소에 둔다. 서버를 새로 만들 때는 Terraform 이 네트워크와 인스턴스를 만들고, Ansible 이 저장소의 코드를 올리고, 데이터는 R2 에서 가져와 되살린다. 지금 prod 백업 저장소는 200 MB 남짓이다.
A1 이 죽었다고 치고 맥북이 그 역할을 넘겨받는 연습도 해 봤다. 마지막 백업을 받아 맥북에서 사이트를 다시 띄우기까지 5분 남짓 걸렸다.
OCI 가입을 넘어, 다음 통곡의 벽은 A1 용량이었다
계정이 생겼다고 바로 서버가 생긴 것도 아니다. 오사카 리전에 A1 무료 자원이 비어 있지 않아 인스턴스 생성시도 과정에서 용량 부족(Out of host capacity) 오류가 났다. Terraform apply 를 스크립트로 재시도 하도록 걸어 두고 3,132번, 70시간 만에 겨우 만들수 있었다.
나중에 계정을 사용한 만큼 내는 유료 계정(Pay As You Go)으로 바꾸고 나서 인스턴스를 다시 만들어 보니 1분도 걸리지 않았다.(허무하다…) 유료 계정(PAYG) 이어도 Always Free 자원은 그대로 무료다. 대신 무료 범위를 넘는 자원이 실수로 생기지 않게 할당량(Quota)으로 막아 두고, 예산 알림을 1달러에 걸어 두었다.
# Description: Always Free 한도 밖 리소스 생성 금지 (A1 2 OCPU/12 GB, 블록 420 GB, 백업 5)
zero compute-core quotas in tenancy
zero compute-memory quotas in tenancy
set compute-core quota standard-a1-core-count to 2 in tenancy
set compute-core quota standard-a1-core-regional-count to 2 in tenancy
set compute-memory quota standard-a1-memory-count to 12 in tenancy
set compute-memory quota standard-a1-memory-regional-count to 12 in tenancy
zero block-storage quotas in tenancy
set block-storage quota total-storage-gb to 420 in tenancy
set block-storage quota backup-count to 5 in tenancy
set block-storage quota volume-count to 2 in tenancy
zero database quotas in tenancy
zero load-balancer quotas in tenancy
zero filesystem quotas in tenancy
zero object-storage quotas in tenancyCode language: Bash (bash)

처음 그림에서 바뀐 것들
큰 틀은 처음 그림 그대로다. Cloudflare 가 앞에 서고, 요청은 터널로 들어오고, A1 한 대가 전부 돌리고, 백업은 R2 에, 코드는 GitHub 에 있다. 다만 내부 변경사항은 꽤 많았다.
- 운영체제와 컨테이너 런타임: Ubuntu 와 Docker 에서 Oracle Linux 10 과 Podman 으로
- 웹 서버: Caddy 에서 nginx 로
- 관리 접속: Bastion 의 Managed SSH 에서 Port-forwarding 세션으로. Oracle Linux 10 에는 Managed SSH 에 필요한 Bastion 플러그인이 없다
- 데이터 위치:
/srv/blog/data에서 사용자 홈 아래~/blog-data로 - 개발 환경: 맥북의 Podman Desktop 에서 같은 구성을 dev 로 돌리고(Podman Desktop 으로 Docker Desktop 을 바꾼 이야기), 글 작성에 쓰는 로컬 AI 도 맥북에서 돈다
하나하나 바꾼 이유가 있는데, 그 이야기는 따로 정리할 생각이다. 어쨌든 매달 나가는 서버비 없이 블로그를 다시 쓸 수 있게 됐고, 2년 넘게 멈춰 있던 글쓰기도 이 글로 다시 시작한다.