self-hosted 글쓰기 앱 bookstack demo

Self-Hosted 글쓰기, 위키 웹앱 Bookstack을 Docker-compose로 설치하기

컴퓨터, 소프트웨어 2024년 1월 12일

북스택(Bookstack)이란?

북스택(Bookstack)이란 글쓰기, 정보를 정리하기 좋은 오픈소스, self-hosted 앱입니다. 사용법이 쉬우면서도 글쓰기에 필요한 기능들은 꽤 갖추고 있습니다. 저는 시나리오나 소설, 에세이 등 문학적인 글을 작성할 때 사용합니다.

BookStack
BookStack is a simple, open-source, self-hosted, easy-to-use platform for organising and storing information.

Bookstack 홈페이지

GitHub - BookStackApp/BookStack: A platform to create documentation/wiki content built with PHP & Laravel
A platform to create documentation/wiki content built with PHP & Laravel - GitHub - BookStackApp/BookStack: A platform to create documentation/wiki content built with PHP & Laravel

Bookstack Github 페이지

메모용 앱은 조플린을 사용하고 있는데 문학적인 글을 분리해서 작업하고 싶은 마음에 이것저것 찾다가 Bookstack으로 정착하게 됐습니다. Bookstack의 외관이나 기능에 대해서는 이전에 올린 포스팅을 참고하세요.

시나리오, 소설, 에세이 작성 어플 스크리브너 버리고 Bookstack으로 정착
시나리오, 소설을 쓰기위한 다양한 글쓰기 어플을 찾다가 결국 bookstack으로 정했습니다. scrivener는 기능이 훌륭하지만 온라인 작업이 안되고 UI가 별로입니다. self-hosted 오픈 소스 어플 중에서 다양한 기능을 제공하는 bookstack으로 정했습니다.

Bookstack 소개

개발자가 데모 버전의 웹페이지도 공개해 두었습니다. 웹페이지에 접속해서 디자인이나 구성을 살펴보세요. 비로그인 상태에서 살펴볼 수 있습니다.

BookStack Demo

Bookstack Demo

Bookstack 설치 준비

Bookstack은 Self-hosted앱이다 보니 네트워크에 대해 어느 정도 지식이 있어야 하며, 도커를 이용해서 설치합니다. 저는 오라클 클라우드 A1(우분투 20.04)에 설치해서 사용합니다.

준비 1 : 도메인

도메인이 있다면 A레코드를 미리 설정해두어야 합니다. 혹시라도 도메인 구매하시려는 분이 있으시다면 그냥 처음부터 Cloudflare에서 구매하시길 추천합니다. 환율이 오락가락하는데 국내 업체는 오를 때는 전광석화고 내려갈 때는 나무늘보네요.

서버(저의 경우는 오라클 A1)의 IP 주소가 123.123.123.123이고, 연결하고 싶은 도메인 주소가 bookstack.bonik.me라고 가정하겠습니다. 클라우드 플레어의 도메인 DNS 설정에서 bookstack.bonik.me의 A레코드를 123.123.123.123으로 설정하면 됩니다.

A레코드 연결 예

만약 도메인이 없다면 123.123.123.123:6875 이런식으로 접속하면 됩니다. 6875가 bookstack이 사용하는 기본 포트입니다. 이 때, 서버에서 TCP 6875포트를 열어줘야 합니다.

준비 2 : 리버스 프록시 설정(NPM)

도메인을 사용하는데 bookstack.bonik.me:6875 이런식으로 접속하고 싶진 않을 겁니다. 포트를 감추기 위해서는 리버스 프록시를 설정해야 합니다. 리버스 프록시를 하는 어플은 여러 종류가 있는데 사용법이 쉬운 Nginx Proxy Manager를 기준으로 설명합니다.

Nginx Proxy Manager에서 리버스 프록시 설정

bookstack.bonik.me 도메인을 넣어주고 Forward Hostname / IP 항목에서는 localhost나 도커 브릿지 네트워크의 게이트웨이를 넣어주면 됩니다. 브릿지 네트워크의 게이트웨이가 뭔지 모른다면 Portainer같은 도커 관리 앱이나 아래 명령으로 알아낼 수 있습니다.

docker network inspect bridge | grep "Gateway"
도커 브릿지 네트워크의 게이트웨이 알아내기

준비 3 : SSL 인증서 설정(NPM)

http로 접속하면 브라우저가 자꾸 잔소리하는 시대다보니 https로 접속해야 기분이가 좋습니다. NPM에서 SSL 인증서를 새로 발급받거나 기존에 발급받은 와일드카드 인증서(*.도메인.com 같은 형태)를 이용하면 됩니다. NPM 인증서 발급법은 여기저기 많이 있으니 생략합니다.

Nginx Proxy Manager에서 SSL 설정

준비 4 : 메일 smtp 설정 메모해두기

bookstack에서 메일 기능을 사용하지 않을거라면 무시해도 됩니다. 그렇지만 세팅하는 김에 같이 해둬서 나쁠 건 없습니다. 저는 도메인 메일로 zoho메일을 사용하는데 각자 사용하는 메일에 맞는 smtp 설정을 메모해둡니다. 도메인메일이 없어도 gmail은 smtp기능을 사용할 수 있습니다.

# Zoho메일 smtp 설정
호스트 : smtp.zoho.com
포트 : 587(TLS일 때), 465(SSL일 때)
유저 : 메일주소
암호 : 암호(app용 별도 암호 생성)

# Gmail smtp 설정(imap사용 설정해야 함)
호스트 : smtp.gmail.com
포트 : 587(TLS일 때), 465(SSL일 때)
유저 : 메일주소
암호 : 암호(app용 별도 암호 생성)

도커 컴포즈로 북스택 설치하기

저는 도커 어플을 /home/docker경로에 몰아 넣습니다. 에디터는 nano를 사용합니다.

Bookstack 폴더 및 도커 컴포즈 파일 생성

# root 사용자로 변경
sudo -i

# 도커 폴더내에 bookstack 폴더 생성
mkdir /home/docker/bookstack

# 생성한 폴더로 이동
cd /home/docker/bookstack

# docker-compose.yml 파일 생성
nano docker-compose.yml

Docker-compose.yml 파일의 내용

이메일을 사용하지 않는 버전의 docker-comopse.yml 파일입니다. 이메일은 smtp를 이용해 보낼 수 있습니다.

version: "2"
services:
  bookstack:
    image: lscr.io/linuxserver/bookstack
    container_name: bookstack
    environment:
      - PUID=1000
      - PGID=1000
      - APP_URL=${APP_URL}
      - APP_DEFAULT_DARK_MODE=${APP_DEFAULT_DARK_MODE}
      - DB_HOST=bookstack_db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=${DB_PASS}
      - DB_DATABASE=bookstackapp
      - MAIL_DRIVER=${MAIL_DRIVER}
      - MAIL_HOST=${MAIL_HOST}
      - MAIL_PORT=${MAIL_PORT}
      - MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
      - MAIL_USERNAME=${MAIL_USERNAME}
      - MAIL_PASSWORD=${MAIL_PASSWORD}
      - MAIL_FROM=${MAIL_FROM}
      - MAIL_FROM_NAME=${MAIL_FROM_NAME}
    volumes:
      - ./bookstack_app_data:/config      
    ports:
      - 6875:80
    restart: unless-stopped
    depends_on:
      - bookstack_db
  bookstack_db:
    image: lscr.io/linuxserver/mariadb
    container_name: bookstack_db
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - TZ=Asia/Seoul
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - ./bookstack_db_data:/config
    restart: unless-stopped

bookstack용 docker-compose.yml의 내용

.env 파일 작성 및 편집

항목이 많아서 편집할 것과 아닌 것의 구분이 좀 힘들것 같아서 .env 파일을 따로 생성하도록 했습니다.

# .env파일 생성
nano .env

bookstack용 .env 파일 생성

.env 파일의 내용

.env 파일의 내용은 아래를 붙여넣기 후에 자신의 설정에 맞게 편집하면 됩니다. # 이후는 주석이니 지워도 되고 놔둬도 됩니다.

# Basic Settings
APP_URL=https://bookstack.bonik.me # 본인 URL에 맞게 수정
APP_DEFAULT_DARK_MODE=true # 기본 테마를 다크모드로

# DB Settings
DB_PASS=암호설정
MYSQL_ROOT_PASSWORD=암호설정
MYSQL_PASSWORD=암호설정

# Mail Settings
MAIL_DRIVER=smtp
MAIL_HOST=smtp.zoho.com
MAIL_PORT=587
MAIL_ENCRYPTION=tls
MAIL_USERNAME=메일유저 # e.g) abc@def.com
MAIL_PASSWORD=메일암호
MAIL_FROM=메일유저 # 무료 서비스라면 MAIL_USERNAME에서 변경못하는 경우가 많음
MAIL_FROM_NAME=메일보내는사람이름 # e.g.) Bookstack

bookstack용 .env의 내용

Bookstack 실행

이제 모든 준비가 끝났으니 도커를 실행하면 됩니다.

docker compose up -d

# 과거버전의 도커 컴포즈라면
docker-compose up -d

bookstack docker-compose.yml 실행

Bookstack 접속

이미지를 다운받고 컨테이너가 실행되고 나면 https://bookstack.bonik.me으로 접속할 수 있습니다. 최초 설치시에는 1분 이상 걸릴 수도 있습니다.

bookstack 로그인 페이지

최초 로그인 방법

bookstack을 설치한 후에 최초 접속하려면 메일 admin@admin.com, 비밀번호 password를 입력하면 됩니다. 관리자로 최초 접속하고 나면 우측 메뉴 버튼을 눌러 여러가지 설정을 할 수 있습니다.

bookstack 메뉴 버튼

한국어 설정

My Accout - Profile Details - Language에서 언어를 한국어로 설정할 수 있습니다.

bookstack 언어 설정

한국어 번역 누락된 부분이 많이 있는데 저는 .php파일을 수정해서 사용합니다. 한국어 언어파일의 경로는 도커 컨테이너 내부의 /app/www/lang/ko입니다. 하는 방법은 생략합니다. 할 줄 아는 분이라면 어차피 이 글 볼 일이 없을 거 같아서...

커스텀 CSS 설정

다른 기능은 차차 알아가시리라 믿고 외관 설정을 위해 커스텀 CSS 설정하는 것만 설명합니다. Settings - customization 으로 들어가면 가장 하단에 Custom HTML Head Content라는 곳이 보입니다. 이 곳에 HTML 헤드에 들어가는 소스를 넣으면 됩니다. 이 곳에 넣은 코드는 원래 코드보다 우선적으로 적용이 됩니다.

제가 작성해서 사용하는 코드는 다음과 같습니다. 그냥 붙여넣기 해서 테스트 해보셔도 됩니다. 마음에 안드는 부분은 삭제하거나 본인이 원하는대로 직접 수정해서 사용하시면 됩니다. 고운 폰트는 구글웹폰트를 사용했습니다.

<link href="https://fonts.googleapis.com/css?family=Gowun+Batang" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Gowun+Dodum" rel="stylesheet">
<style>
.logo-text { font-size: 1.4rem; }
h1 { font-size: 2.2rem; }
h2 { font-size: calc(2.2rem * 0.9); } /* 90%의 비율로 조절 */
h3 { font-size: calc(2.2rem * 0.8); } /* 80%의 비율로 조절 */
h4 { font-size: calc(2.2rem * 0.7); } /* 70%의 비율로 조절 */
h5 { font-size: calc(2.2rem * 0.65); } /* 65%의 비율로 조절 */
h6 { font-size: calc(2.2rem * 0.52); } /* 52%의 비율로 조절 */  
  
.page-content h1 { font-size: 2.2rem; }
.page-content h2 { font-size: calc(2.2rem * 0.9); } /* 90%의 비율로 조절 */
.page-content h3 { font-size: calc(2.2rem * 0.8); } /* 80%의 비율로 조절 */
.page-content h4 { font-size: calc(2.2rem * 0.7); } /* 70%의 비율로 조절 */
.page-content h5 { font-size: calc(2.2rem * 0.65); } /* 65%의 비율로 조절 */
.page-content h6 { font-size: calc(2.2rem * 0.52); } /* 52%의 비율로 조절 */

.py-m {
  padding-top:8px !important;
  padding-bottom:8px !important;
}
.pt-xl { padding-top: 16px !important; }
  
.mt-m { margin-top:0px !important}  
  
.entity-list.compact h4, .entity-list.compact a { font-size: 1rem; }
.justify-space-between { font-size: 1.1rem; }
.card-title { font-size: 1.1rem; }
html.dark-mode header .header-links { font-size: 1rem; }
html.dark-mode .tri-layout-mobile-tab { font-size: 1.1rem; } 
.entity-list.compact .entity-list-item p { font-size: 1rem; }
.grid-card p { font-size: 1rem; }

.entity-list-item, .icon-list-item { padding: 4px 16px } 
  
body {
  --font-body: 'Gowun Batang', serif;
  --font-heading: 'Gowun Dodum', sans-serif;
  font-size: 1rem;  
}
p { font-size: 1rem; /* 원하는 폰트 크기로 변경 */ }

p,ul,ol,pre,table,blockquote {
    margin-top: .3em;
    margin-bottom: .5em
}

small, p.small, span.small, .text-small { font-size: .9rem; }
label { font-size: .9rem; }

.input-base, input[type="text"], input[type="number"], input[type="email"], input[type="date"], input[type="search"], input[type="url"], input[type="color"], input[type="password"], select, textarea, .fake-input { width:200px }  
  
</style>

bookstack 커스텀 헤드(커스텀 CSS를 위한)

마치며...

이제 bookstack을 둘러 보면서 기능도 익히고 열심히 작업하시면 됩니다. plex가 그렇고 kavita가 그렇고 늘 그랬듯이 세팅이 끝나면 정작 이용은 잘 안하게 되겠지만요. ㅋ

태그

BoniK

협업, 작업의뢰, 레슨 및 기타 문의 : mail@bonik.me