Ghost로 블로그 제작하기

Ghost로 블로그 제작하기

Ghost란?

Ghost는 2013년 만들어진 비영리 오픈소스 Headless 블로그(CMS) 프로젝트이다. nodejs 기반 풀 스택 퍼블리싱 플랫폼으로 사용자는 백엔드와 프론트엔드 모두를 커스터마이징 할 수 있다.

나는 네이버 블로그, 티스토리, 브런치, 워드프레스, 미디엄, Jekyll blog, Notion blog, Substack 등을 모두 고려선상에 넣고 적당한 블로깅 플랫폼을 찾아다니다 우연히 Ghost에 대해 접하게 되었고 아직 쓴 지는 오래되지 않았지만 만족하면서 쓰고 있다.

Ghost를 사용하는 블로그는 OpenAI, Cloudflare, Mozilla, DuckDuckGo, DigitalOcean, Stanford University, Buffer 등이 있다. 내가 좋아하는 연구 기관이나 프로젝트, 기업에서 많이들 쓰고 있다.

Ghost 블로그의 이점

왜 Ghost로 블로그를 만드는 것을 추천하는지 이유를 적어보겠다.

  1. 쉬운 설치법
    특히 digitalocean에서 원 클릭 설치 가능.
  2. 더불어 매우 쉬운 업데이트법.
    ghost update 하나로 업데이트가 되고 ghost update --rollback으로 롤백이 바로 된다. 동영상 업로드 같은 매우 마음에 드는 기능도 오늘 딱 생겼는데 ghost stop으로 서버 끄고 ghost update하고 ghost start로 서버 다시 켰더니 그냥 업데이트가 되버리는 미친 편의성..
  3. 구독 기능 기본 구현
    Mailgun 설정만 해주면 구독자에게 일괄 메일 전송 기능 사용 가능.
  4. 다른 설치형 블로그도 대부분 비슷하지만, 소스코드 하이라이팅과 katex 수식 입력을 할 수 있다. 다만 ghost는 단순히 settings/code injection에 site header, site footer에 적당히 HTML을 입력해줌으로써 더 간단하게 설정 가능하다.
  5. 본인 블로그 주소/ghost로 접속하면 관리자 페이지가 나오고 여기에서 여러 설정과 글 쓰기를 할 수 있다. 디자인 좋고 활용성 좋다. ghost 자체 에디터도 꽤 쓸만한 편이다.
  6. 기본 테마(casper)부터 디자인이 상당히 좋다.
  7. Ghost(Pro) 사용하지 않고 직접 구축할 경우 도메인 1년 25달러, digitalocean 1달 6달러(5달러+백업 1달러), mailgun 0.8달러/1000mail 정도의 비용으로 유지할 수 있다. Ghost(Pro)를 사용하면 custom theme까지 사용하면 월 25달러 정도로 비용이 꽤 드는 편이나, Pro를 사용하면 여러 설정을 본인이 하지 않고 간편하게 할 수 있을 것 같다. (Pro는 직접 써보지 않아서 실제로 그런지는 모른다!)
  8. 빠른 구동. ghost restart가 최저사양 서버에서 5초도 안되서 실행이 될 정도다.

수고를 들이기 싫고 자본이 충분하면 Ghost(Pro), 그게 아니면 Ghost로 직접 블로그를 구축하는 것을 추천한다.

다른 플랫폼과 비교

난 가장 처음 Github Pages로 Jekyll blog를 만들어 썼었고, 이후 vercel을 통해 nobelium(notion에 쓴 글을 nextjs로 옮겨주는 블로그 만들어주는 프로젝트이다)을 구동했다.

둘 모두 무료에 마크다운 지원되고 있을만한 기능은 대부분 있다는 장점이 있으나 구독 기능이 없고 정적 페이지 자체의 한계를 좀 느껴서 다른 블로그 플랫폼을 찾아봤었다. 구독제가 있는 Substack을 후보군으로 잡고 구글링을 하다 ghost를 우연히 발견했는데 기본 테마부터 디자인이 너무 좋고 내가 필요로 하는 기능은 다 있길래 ghost로 블로그를 만들기로 정했다.

이후 구독 시스템까지 있는 정적 사이트 기반 Gatsby를 발견하고 조금 끌렸는데 음.. 개츠비를 발견했을 당시 이미 ghost blog 도메인 구매+digitalocean 설정까지 전부 끝냈을 때인데다 아무래도 ghost 쪽이 더 확장하기 편할 것 같아 선택했다.

고스트(Ghost)로 블로그 만들기에서 Substack 등 내가 주목하던 블로깅 플랫폼과 Ghost의 비교를 참고할 수 있다. 해당 자료를 아래에 첨부했다.

------2021-12-14-150858
------2021-12-14-150832

Ghost 블로그 제작법

1. 도메인 구매

난 bigdaddy에서 milkclouds.work 도메인을 구매했다. 가격 보고 적당한 거 골라 쓰자.

digitalocean이란?

digitalocean이란 호스팅을 해주는 꽤 큰 기업인데, 나처럼 블로그나 웹사이트 만드려고 쓰는 사람도 있고 보니까 심지어 Minecraft 서버까지 원클릭으로 설정 가능한 듯하다.

2. digitalocean 가입

DigitalOcean Referral Badge
위의 뱃지를 클릭해 가입하면 나에게 25달러, 가입한 사람에게 100달러가 60일간 제공된다. 이틀 간 삽질하면서 얻은 경험 정리한 글이니 읽어보고 도움이 될 듯하다면 위의 referral link 통해 가입 부탁드립니다.

3. digitalocean 설정

Droplet을 아래와 같이 만든다.
난 한국에 가까운 싱가폴 서버로 하고, Monitoring를 켜뒀다. Monitoring은 켜두면 좀 더 Enhanced된 metric을 그래프로 확인할 수 있다고 한다. How to Install the DigitalOcean Metrics Agent 참고.

------2021-12-14-155153

그나저나 5$짜리 서버보다 더 좋은 서버 사용해도 괜찮지 않을까 하는 생각이 좀 들긴 하는데 음.. 알아서 설정하자.

ssh 설정은 아래 과정을 따르면 된다.

  1. 로컬 컴퓨터(이 글을 보는 독자의 컴퓨터)에서 ssh-keygen 실행(terminal을 켜자마자 cd .ssh를 실행함으로써 C:\Users\유저명\.ssh에서 실행하는 것을 권장함. 이는 rsa의 공개키와 비밀키를 모두 .ssh 경로에 저장해두기 위함임.)
  2. 적당히 이름 입력(blog) 등
  3. blog.pub 복사해서 digitalocean ssh 추가하는 데다 붙여넣기한다.

아래는 예시 스크린샷
------2021-12-14-164557

이후 로컬 컴퓨터에서 아래와 같이 .ssh/config 파일을 설정하면 ssh blog 커맨드 하나만으로 digitalocean 서버에 매우 간단하게 접속 가능하다.

Host blog
    HostName (digitalocean아이피)
    User root
    IdentityFile C:\Users\유저명\.ssh\blog

VSCode의 Remote SSH extension으로 digitalocean 서버에 접속할 때, 1GB RAM으로는 RAM이 모자란지 VSCode을 켜뒀을 때 Ghost 페이지가 제대로 돌아가지 않으니 주의하자. RAM이 원인이 아닐 수도 있지만 아무튼.. VSCode로 접속해서 소스코드 수정할 때는 웹페이지가 (반강제적으로) 꺼져 있다고 생각하면 된다.

이후 ssh로 연결하고 1. 도메인 설정 2. 이메일 설정 해주면 자동으로 digitalocean의 ghost 설정 툴이 설치를 해준다. 이후 도메인 뒤에 ghost를 붙여 접속하면 관리를 해줄 수 있다. 예를 들어 https://milkclouds.work/ghost

관리 페이지에서 기초 설정을 해준 후에는 자신이 사용하는 도메인을 통해 블로그에 접속할 수 있다!

------2021-12-14-171905

4. digitalocean 서버를 도메인에 연결

digitalocean의 droplet 아이피를 가져다, 도메인 DNS 설정으로 연결하면 된다.
Bigdaddy에서 유형 A,이름 @, 값 droplet 아이피, TTL은 기본설정으로 냅두고 설정하면 된다. 이후 짧으면 수십분, 길면 반나절쯤 기다리면(바로 되는 게 아니다!) DNS 정보가 전파되며 전세계에서 구매한 도메인을 통해 digitalocean 서버에 접속할 수 있게 된다.

5. Ghost-cli의 간단한 사용법

  1. ssh 통해 digitalocean의 droplet에 연결(내 글에서 알려준 방법을 따라왔다면, 로컬 컴퓨터에서 터미널 열고 ssh blog 입력하는 것만으로 접속이 될 것이다)
  2. 기본적으로 root 계정으로 로그인이 된다. ghost 서버 start, stop, restart 등을 하고 싶다면 sudo -i -u ghost-mgr 커맨드를 통해 ghost-mgr 유저로 계정을 변경해야 한다.
  3. digitalocean의 ghost 기본 설치 경로는 /var/www/ghost이다. cd /var/www/ghost를 통해 해당 경로에 접속하고, ghost-mgr 계정을 사용중인지 확인한다.
  4. 시험삼아 ghost --version을 입력해보자. 나는 아래와 같이 나온다. ghost ls를 실행했을 때 서버가 돌아가고 있다는 것까지 확인이 되면, 성공이다.
Ghost-CLI version: 1.18.1
Ghost version: 4.27.2 (at /var/www/ghost)
  1. ghost 파일을 여럿 변경하며 고스트 서버를 재시작할 일이 생기면, /var/www/ghost에서 ghost restart를 실행한다.

6. Email Subscription 설정

Settings/Email newsletter/Email newsletter settings에서 Mailgun setting을 해준다. mailgun에 가입하고, sandbox**.mailgun.org 형태의 도메인을 복사해 넣고, private api key를 찾아 복사해 넣으면 된다.

위처럼 sandbox 도메인 사용하면 production에 제대로 못 쓴다. 난 그걸 몰라서 몇 시간 동안 도대체 왜 이럴까 Ghost 자체 에러로그까지 뒤져보고 했는데, Mailgun에서 Sending/Logs를 보니 실패 로그가 쫙 쌓여있었다. Reject 원인은 아래와 같이 나온다.

"reject": {
		"reason": "Sandbox subdomains are for test purposes only. Please add your own domain or add the address to authorized recipients in Account Settings.",
		"description": ""
	},

아니 mailgun에서 제공한 sandbox 도메인은 test purpose only여서 이메일이 안 보내지는거면 test purpose only여서 그렇다고 ghost에서 알려줘야지 ghost는 그냥 대뜸 "오류가 나서 안됨 다시 시도하셈" 이것만 뱉으면 뭐 어쩌자는거...? 삽질하다 찾은 당장 이메일 설정하는데는 쓸모없는 정보 중에는 너무 Sign in 시도를 하면 그 아이피가 차단된다는 것만 있다.

6.2 Mailgun에서 Domain 추가

Mailgun에서 Sending/Domains에서 Add Domain을 누른다. (이게 안 보이면 결재 정보를 입력 안 해서 안 보이는 것일 가능성이 높다.)
그리고 도메인으로 본인 사이트 주소를 넣고(보통 고스트 세팅에서 Email Newsletter에 이메일 정보가 noreply@milkclouds.work처럼 설정이 되어있기 때문), 하라는 대로 도메인의 DNS 설정을 싹 다 한다. 도메인 구입한 사이트(내 경우 bigdaddy) 가서 txt 넣고 뭐 넣고 CNAME 넣고 하면 된다. 잘 모르겠으면 아래 스크린샷처럼 설정하면 된다.

------2021-12-14-163901

이후 /var/www/ghost/config.production.json에서 아래 부분을 수정한다.

"mail": {
    "transport": "Direct"
  },

아래와 같이 수정하는데, 비밀번호는 아래 스크린샷 위치로 따라 들어가서 확인하면 된다.
------2021-12-14-163146

"mail": {
    "transport": "SMTP",
    "options": {
      "service": "Mailgun",
      "auth": {
        "user": "postmaster@milkclouds.work",
        "pass": "비밀번호"
      }
    }
  },

7. Google Search Engine 등록

Google Search Engine에 등록하러 가서 "도메인으로 추가" 같은거 누르면 GoDaddy랑 연동해서 원클릭으로 사이트 Authorization이 된다. 너무 편리한데?

나중에 Godaddy 들어가서 확인하면 DNS에 txt로 google-site-verification이 자동으로 추가가 되어있다. 이걸로 인증을 하나보다.

8. 네이버 서치어드바이서 등록

한국인이 가장 많이 쓰는 검색엔진이 네이버인지라 네이버에도 자신의 사이트를 등록해 두는 것이 좋다. 네이버 서치어드바이저 들어가서 본인 도메인을 입력하면, 인증을 위해 <meta name="naver-site-verification"~~> 꼴의 스크립트를 site header에 넣으라고 요구한다. 하라는 대로 settings의 code injection에서 site header에 넣어두면 바로 인증이 된다.

이후 rss(본인 사이트/rss), sitemap(본인 사이트/sitemap.xml)을 제출하고 검증 탭에서 내 웹페이지가 잘 만들어져 있나 확인해보자.
------2021-12-14-181609

9. 각종 기능 구현

일단 Settings/Code Injection/Site Header에 내가 뭘 쓰고 있는지부터 소개한다. 잘 모르겠으면 저거 복붙하고 google anaylytics 일련번호 수정하고 나눔고딕 쓰려면 후술할 폰트 나눔고딕으로 바꾸기만 따라하면 된다. 내가 사용하는 기능은 Google Anayltics, Highlight.js(소스코드 하이라이트), Katex(수식 삽입), 나눔고딕이다.

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-일련번호"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-일련번호');
</script>

<!-- Highlight.js -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/agate.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<style>
  pre {
    word-wrap: normal;
    -moz-hyphens: none;
    -ms-hyphens: none;
    -webkit-hyphens: none;
    hyphens: none;
    font-size: 0.7em;
    line-height: 1.3em;
  }
  pre code, pre tt {
    white-space: pre;
  }
</style>

<!-- Katex -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.css" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.js" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>

<!-- font -->
<link href='https://rsms.me/inter/inter.css' rel='stylesheet' type='text/css'>
<link href='https://spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-kr.css' rel='stylesheet' type='text/css'>
<style>
body,  
h1, h2, h3, h4, h5, h6,
.main-nav a,
.subscribe-button,
.page-title,
.post-meta,
.read-next-story .post:before,
.pagination,
.site-footer,
.post-full-content,
.post-card-excerpt,
.post-full-custom-excerpt,
[class^="icon-"]:before, [class*=" icon-"]:before
{
font-family:
  "-apple-system", "BlinkMacSystemFont","Apple SD Gothic Neo",
  "Inter", "Spoqa Han Sans", "Segoe UI", Sans-Serif,
  "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
</style>

Google Analytics 삽입

https://ghost.org/integrations/google/을 참고하면 되는데, 요약하자면 그냥 google anaylytics 가입하고 삽입하라고 나오는 스크립트 복사해서 Settings/Code Injection/Site Header에 넣으면 된다.

소스코드 하이라이트

위에 이미 소개한 대로 highlight.js를 site header에 넣으면 된다.

수식 입력

위에 이미 소개한 대로 katex를 site header에 넣으면 된다.
만약 $$도 inline equation의 delimeter로 쓰고 싶다면 아래 소스코드를 대신 넣자!

<!-- KaTex -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js" integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

자동 트위터 publication 설정

Untitled-7
Settings/Integration/Zapier에서 Share new posts to Twitter 사용 설정하면 된다. Zapier 가입하고 로그인 몇번 해주면 간단히 설정된다.

Disqus 삽입

댓글 기능을 넣기 위해 Disqus를 사용할 수 있다.
https://ghost.org/integrations/disqus/을 참고하면 된다. 단순 code injection 외에 hbs 파일을 수정해야 해서 쪼금 더 복잡하다.

telegram 기반 댓글

https://comments.app/ 들어가서 삽입하라고 주는 script를 post.hbs에 넣는다.

graphcomment

graphcomment에서 제시하는 universal code를 post.hbs에 삽입하되 uid: "ghost-{{comment_id}}"로 수정한다.

table of contents 추가하기(안됨)

2021-12-14 기준 Ghost 공식 Tutorial을 따라했을 때 되지 않는다. Casper Theme에서 블로그 글을 열었을 때 post-content classs 자체가 존재하질 않는데 흠... Tutorial이 outdated되어서 테마 업데이트 반영이 안 된 듯하다.

폰트 나눔고딕으로 바꾸기

먼저 /var/www/ghost/content/themes/casper/assets/built/screen.css--font-serif:Georgia,Times,serif부분을 --font-serif:로 바꿔버린다. 이 작업을 수행하지 않으면 제목의 폰트만 바뀌고 본문의 폰트가 바뀌지 않는다. 참고

이후 아래 스크립트를 site header에 삽입한다.

출처 Ghost 블로그 사용 팁 모음

<link href='https://rsms.me/inter/inter.css' rel='stylesheet' type='text/css'>
<link href='https://spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-kr.css' rel='stylesheet' type='text/css'>
<style>
body,  
h1, h2, h3, h4, h5, h6,
.main-nav a,
.subscribe-button,
.page-title,
.post-meta,
.read-next-story .post:before,
.pagination,
.site-footer,
.post-full-content,
.post-card-excerpt,
.post-full-custom-excerpt,
[class^="icon-"]:before, [class*=" icon-"]:before
{
font-family:
  "-apple-system", "BlinkMacSystemFont","Apple SD Gothic Neo",
  "Inter", "Spoqa Han Sans", "Segoe UI", Sans-Serif,
  "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
</style>

다크모드

원래 다크모드 Toggle 기능을 만들고 싶었는데, 고스트 포럼 글에 따르면 운영체제 테마에 따라 다크모드가 자동으로 활성화 된다고 한다. 실제로 casper 테마 screen.css를 읽어보면 다크모드를 강제 활성화시키고 싶으면 어떤 코드를 site header에 넣으라고 주석에서 제시하고 있다. 아무튼 대충 찾아봤을 때 토글 기능은 어떻게 넣는지 안 나오고, 대충 알아서 운영체제 테마 따라 바뀌게 냅뒀다.

post.hbsif featured_image 부분을 if 0로 만들어 버린다. /var/www/ghost/content/theme/casper/에 있을 것이다. 참고

한글 url 사용

고스트 블로그에서 한글 URL 적용하는 방법(4.9.1 버전 방법 업데이트)
고스트 블로그에서 한글 URL 사용시 영어로 자동 변환되는 문제를 해결하고 한글 URL을 적용시키는 방법을 알아봅니다.

위 블로그 글 따라서, /var/www/ghost/versions/4.30.1/node_modules/@tryghost/string/lib/slugify.js와  /var/www/ghost/versions/4.30.1/node_modules/@tryghost/validator/lib/validator.js을 수정해 주면 된다.

번외

Ghost 블로그를 Nextjs로 옮겨주는 https://github.com/styxlab/next-cms-ghost도 있다. ghost 블로그가 이미 존재해야 거기 있는 포스트를 옮겨오는 구조인듯.

완성 결과

블로그 완성! 일단 외관은 너무 마음에 든다. 근데 편집 과정에서 아무래도 Notion에 밀리는 점이 계속 보인다 ㅠ... ->가 자동으로 화살표 변환이 안 되는 것도 그렇고, Toggle block 안에 뭐 제대로 못 넣는 것도 그렇고, nested listing이 안 되는 것도 그렇고, 수식이 적어도 에디터에서는 원래 형태로 못 생기게 보이는 것도 그렇고, 미리보기에서는 수식이 로딩이 안 되는 것도 그렇고, 고치고 싶은 부분이 많다.

업데이트 방법

Ghost Docs
Everything you need to know about working with the Ghost professional publishing platform.

위의 Docs를 참고하면 되는데, https://ghost.org/docs/update/?v=4.27.2 처럼 버전별로 업데이트 docs를 따로 만들어둔 듯하다. 아마 대부분의 경우는, 진짜 구버전 ghost를 사용하는 게 아니면 ?v=4.27.2를 url에 붙이고 들어가지 않아도 별 문제는 없겠지만 혹시 모르니 본인 사용하는 버전별 update 법을 찾아서 참고하자.

매우 간단히 정리하면(요약일 뿐이다. 다시 말하지만 혹시 모르니 자신의 버전별 공식 update docs를 참고하자) 1. 백업 2. ghost update 실행 이 두 가지 스텝이 업데이트 과정의 전부이다. 업데이트까지 진짜 엄청나게 편리한 ghost... 이거 에디터 좀 불편해도 쓸만한 것 같다.

다만 업데이트하면 한글 url 설정, 나눔고딕 설정(casper 테마), disqus이 없어져 버리니 다시 설정하자!

+ 추가

표 못 넣는다는 사람이 있던데 그거 마크다운 문법으로 넣어도 되고 html 소스코드 가져다 넣어도 된다. 마크다운 문법은 직접 찾아보자.

+ 추가

Gatsby와 연동해 Ghost를 CMS로 쓰고 정적 사이트를 외부에 호스팅하는 방법도 있다. https://devbull.xyz/jamstack-ghost-gatsby-netlify-1/ 참고하자.

GitHub - TryGhost/gatsby-starter-ghost: A starter template to build lightning fast websites with Ghost & Gatsby
A starter template to build lightning fast websites with Ghost & Gatsby - GitHub - TryGhost/gatsby-starter-ghost: A starter template to build lightning fast websites with Ghost & Gatsby