목차

nginx와 dokuwiki를 이용해 로컬 개인 위키를 구축해보세요!

시작하기

요즘 스마트폰 덕에 언제 어디서나 다양한 형태의 기록을 할 수 있는 환경이 된 것 같습니다. 모바일이라는 플랫폼 덕도 있지만 사용할 수 있는 글쓰기의 포맷도 다양해졌습니다. 예전에는 워드 같은 문서 포맷 정도가 개인 사용자가 만들 수 있는 문서의 전부였다면, 요즘은 정말 다양하고 개성있는 포맷들이 등장했습니다(그렇다고 워드가 구닥다리란 소리는 절대절대 아닙니다! 워드도 사용하기 따라서는 무지막지한 툴이 되죠).

트위터나 페이스북을 이용해 짧고 개인적인 글이 작성되고, 차곡차곡 기록이 됩니다. 블로그는 조금 더 조직적이고 짜임새 있는 글을 작성할 수 있습니다. 인터넷에 저장되는 문서(구글독스, 에버노트, …)들도 있습니다. 쉽게 협업과 공유가 가능하며 동기화도 됩니다.

개인적인 잡담 정도를 나누는데 있어서는 마이크로블로깅, 트위터나 페이스북이 적당한 것 같습니다. 보다 폭넓은 글을 쓸 때는 블로그가 유용합니다. 허나 제 쓸데없이 까다로운 입맛에는 블로그조차도 뭔가 아쉬운 것이 있었습니다. 그러던 중 '위키(wiki)'라는 매체를 만났습니다. 블로그와는 또다른 매력적인 글쓰기 매체임에 틀림없습니다.

제가 알기로는 블로그는 개인사의 기록, 위키는 다수 협업을 통한 체계적인 기록을 각기의 목적으로 합니다. 그러나 블로그에 전문적인 지식을 체계적으로 적을 수도 있고 공동으로 집필을 할 수도 있습니다. 위키의 경우도 저처럼 개인적으로 사용할 수도 있고 개인적인 기록으로 가득 채울 수도 있습니다. 둘을 확연히 구분짓는 결정적인 차이는 대체 무엇일까? 그건 잘 모르겠습니다. 대체로 블로그에선 '포스팅'이란 시간적인 개념이 붙어 '세월 따라 흐른다'는 느낌이 있지요. 그리고 블로그는 여러 업체에서 무료로 많이 제공하지만, 위키를 무료 제공하는 경우는 잘 보지 못했습니다. 위키는 대개 설치형이네요.

수식 지원, 코드 하이라이트, 미디어 삽입, 문서의 추출과 변환, 자료의 백업과 복구, 확장 기능 등 대부분의 기능은 사실 블로그와 위키의 우열을 가리기 어렵습니다. 개인적으로 느낀 블로그 대비 위키의 매우 큰 장점은 다음과 같습니다.

어떤 위키를 사용할까?

위키도 그 개발 철학에 따라 다양한 종류가 있습니다. 어떤 것들은 너무 마이너하고 어떤 것들은 매우 대중적입니다. 쓰기 편하지만 기능상으로 약간 아쉬운 것도 있을 수 있고, 풍부한 기능을 사용하지만 쓰기 쉽지 않은 것도 있을 수 있습니다. 제가 선택한 기준 및 방침은 다음과 같습니다.

  1. 개인 일반 PC에서 개인적으로 운영되는 위키
    • 관리되는 문서는 모두 외부에 비공개되어야 한다.
    • 문서 중 어느 정도 완성도를 가진 문서들을 PDF 등의 다른 포맷으로 공개한다.
    • 공유기 등의 내부 개인 네트워크 하에서는 비교적 자유롭게 접속할 수 있도록 한다.
    • 폐쇄적인 환경이므로 보안에 너무 크게 중점을 두지는 않아도 된다.
  2. 서버 전용의 PC가 아니므로 운영에 PC의 자원을 크게 소모해서는 안된다.
    • 서버와 PHP를 운영하는 것만으로 부담이 크다. 데이터베이스는 사용하지 않는다.
    • 24시간, 365일 운영될 필요는 없다.
  3. 위키 문법의 난이도는 크게 관계 없다. 다 거기서 거기다.
  4. 쉽게 설치하고 쉽게 사용해야 한다. 대규모 문서 작업을 위해 만들어진 그릇이 큰 위키는 안 된다. 운영이 어려워 배보다 배꼽이 커진다.
  5. 상기 상황은 변경 가능할 수 있으므로 가능한 한 유연하고 확장 가능한 형태로 시스템을 구축되어야 한다.

한편 WikiMatrix란 곳이 있습니다. 이 곳에는 왠만한 위키 종류는 다 찾을 수 있습니다. 정말 자기 입맛에 딱 맛는 위키를 고를 수 있도록 매우 디테일한 분류를 해 놓았습니다.

저는 여기서 도쿠위키를 선택했습니다. 도쿠위키는 텍스트 문서 기반으로 데이터베이스를 사용하지 않습니다. 중소형 규모라 저처럼 개인적인 용도로 가볍게 쓰기에 어렵지 않은 위키라고 판단했기 때문입니다. 사실 이전에 미디어위키를 사용해 본 경험이 있는데, 훌륭하긴 하지만 개인적으로 쓰기에는 좀 지나친 감이 있었습니다.

서론이 길었습니다. 이제 도쿠위키를 일반적인 윈도우 PC에 개인 용도로 사용하기 위한 세팅을 기록하겠습니다. 저도 서버 세팅에 대한 지식이 많지 않습니다. 아래 내용은 거의 간단한 레시피 수준입니다. 고급 설정에 대해서는 저도 거의 아는 바가 없음을 미리 알려드립니다.

nginx의 세팅

서버로는 nginx를 사용했습니다. 가볍고 빠른 러시아산(!) 서버로 요즘 많이 쓰이고 있더군요. nginx 세팅은 사실상 nginx의 위키에 다 있는 내용입니다. 그러므로 이 부분은 거의 한글 번역 수준(도 안 될 것)입니다.

다운로드

http://nginx.org/en/download.html 에서 다운로드 받아서 원하는 곳에 압축을 풀면 됩니다. 제 경우 'D:\Server\'에 nginx를 풀고 nginx-1.xxx 디렉토리 이름을 nginx로 변경했습니다. 그러므로 nginx 서버의 절대 경로는 'D:\Server\nginx'입니다.

설정 파일

도쿠위키 및 PHP가 동작하도록 매만져야 합니다. 복잡한 설명이 많았지만 실제로 변경할 내용이 많지는 않았습니다. D:\Server\nginx\conf\nginx.conf 파일을 편집합니다.

PHP를 위한 세팅 추가

파일에서 아래와 같은 부분을 찾아 아래 코드처럼 변경합니다. PHP를 위해 반드시 필요합니다.

   # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
   #
   location ~ \.php$ {
       root           html;
       fastcgi_pass   127.0.0.1:9000;
       fastcgi_index  index.php;
       fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
       include        fastcgi_params;
   }

도쿠위키를 위한 세팅 추가

도쿠위키는 HTML 문서 루트에서 동작시킬 생각입니다. 파일에서 server { … } 구문을 찾습니다. 두 괄호사이에 다음과 같은 코드를 추가1)합니다.

location / {
	 root   html;
	 index  doku.php index.html index.htm;
	 try_files $uri/ @dokuwiki;
}
 
location @dokuwiki {
	rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
	rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
	rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
	rewrite ^/(.*) /doku.php?id=$1 last;
}

아래 코드는 주석을 해제합니다. 만일 없다면 server { … } 사이에 직접 삽입합니다.

location ~ /\.ht {
    deny  all;
}

위키의 내용 보호를 위해 다음 코드도 server { … } 사이에 삽입합니다.

# docuwiki
location ~ /(data|conf|bin|inc)/ {
    deny all;
}

php와의 연동

PHP는 http://windows.php.net/download/에서 thread-safe 윈도우 바이너리를 받으면 됩니다. 압축을 풀면 php-5.xxx 디렉토리가 나옵니다. 저는 이 이름을 'php'로 바꾸어 'D:\Server'에 두었습니다. 그러므로 php의 절대 경로는 'D:\Server\php'입니다. php.ini 파일 편집에 대해서는 생략하겠습니다.

PHP 구문이 정상적으로 동작하는지 확인해보기 위해 phpinfo() 함수를 구동시켜 보겠습니다.

  1. D:\Server\nginx\nginx.exe를 실행시켜 서버가 동작하는지 확인합니다. 웹브라우저에서 'localhost'에 접속해 기본 웹페이지가 출력되는지 확인합니다.
  2. 명령 프롬프트를 열어 D:\Server\php로 이동합니다. 그리고 'php-cgi.exe -b 127.0.0.1:9000'을 입력합니다.
  3. 대충 test.php 파일을 D:\Server\nginx\html 디렉토리에 만듭니다. 아래 test.php 파일 소스를 참고하세요.
  4. 웹브라우저에서 응답이 오는지 확인합니다. 소스는 간단하지만 내용은 엄청 많습니다.
  5. 정상적으로 PHP가 동작하면 test.php 파일은 삭제하세요.
test.php
<?php phpinfo(); ?>

배치 파일 및 자동 실행

배치 파일 만들기

매번 명령창을 열어서 nginx와 php를 구동시킨다면 끔찍합니다. 그러므로 다음과 같은 배치 파일을 몇 개 만들었습니다. 다음 배치 파일은 nginx와 php를 동시에 구동시킵니다.

StartServer.bat
@ECHO OFF
ECHO Starting PHP FastCGI...
set PATH=D:\Server\php;%PATH%
RunHiddenConsole.exe D:\Server\php\php-cgi.exe -b 127.0.0.1:9000
 
ECHO Starting nginx...
cd nginx
..\RunHiddenConsole.exe nginx.exe
cd ..
ECHO ON

다음 배치 파일은 php만 구동시킵니다. 왜인지는 모르겠으나, 장시간 PC를 켜 두면 php-cgi.exe 프로세스가 죽는 일이 일어나 서버 접속이 안 될 때가 있습니다.

StartFastCGI.bat
@ECHO OFF
ECHO Starting PHP FastCGI...
set PATH=D:\Server\php;%PATH%
RunHiddenConsole.exe D:\Server\php\php-cgi.exe -b 127.0.0.1:9000
ECHO ON

다음 배치 파일은 php를 멈춥니다. 윈도우 8에서 taskkill.exe 명령은 관리자 권한이 있어야 호출되므로 관리자 권한으로 실행해야 합니다. 참고로 윈도우 8에서는 ipconfig 명령도 관리자 권한에서만 동작하더군요.

StopFastCGI.bat
@ECHO OFF
REM 관리자 모드에서 실행하세요
taskkill /F /IM php-cgi.exe

다음 배치 파일은 nginx를 멈춥니다. 이 명령은 일반 유저 권한으로도 동작합니다.

StopNginx.bat
@ECHO OFF
ECHO Stopping nginx...
cd nginx
nginx.exe -s stop
cd ..
ECHO ON

RunHiddenConsole.exe은 콘솔 명령은 실행하되, 콘솔창은 완전히 윈도우에서 숨겨 버리는 프로그램입니다. http://redmine.lighttpd.net/attachments/660/RunHiddenConsole.zip 에서 다운로드 받을 수 있습니다.

여러번의 서버 폭파(?) 및 재건으로 인해 스크립트 작성이 매우 귀찮습니다. 미리 'batch'라는 폴더에 bat 파일들을 작성했습니다. batch.zip

자동 실행 하기

탐색기 탐색창에 %APPDATA%를 입력합니다. 그러면 자기 계정의 AppData\Roaming 폴더에 접근할 수 있습니다. 이 폴더는 기본적으로 숨겨져 있습니다. 윈도우 7, 8 기준으로 나머지 Microsoft - Windows - Start Menu - Programs - Startup 폴더에 차례대로 접근합니다. 이 폴더에 StartServer.bat 파일의 바로 가기를 만드세요. 이제 부팅할 때마다 서버는 자동으로 동작합니다.

도쿠 위키의 설정

도쿠위키 다운로드, 설치 과정은 모두 생략하겠습니다. 미디어위키보다는 훨씬 간결하지만 도쿠위키 시스템도 은근히 어렵습니다. 제가 설명할 범위가 아닌 듯합니다. 검색을 활용하세요. 나머지는 제가 현재 사용 중인 도쿠위키 세팅 정보입니다.

사용한 플러그인

플러그인은 보통 다운로드 받아 도쿠위키 루트\lib\plugins 디렉토리에 플러그의 압축을 푸는 것만으로 설치가 끝납니다. 현재 사용중인 플러그인은 두 종류입니다.

comment

comment 플러그인을 사용하면 내부 위키의 일부를 주석으로 처리할 수 있습니다. 정말 주석으로 사용하든지, 아니면 일부의 내용은 아직 숨겨두고자 할 때 사용하면 좋습니다. 주석으로 처리하고픈 구간을 C 문법의 주석처럼 /*와 */로 감싸면 됩니다.

dw2pdf

클리앙에 위키 내용을 공개할 때 PDF로 만들어서 문서 포맷을 변경합니다. 이 때 dw2pdf 플러그인을 사용하여 위키 내용을 아주 편하게 PDF로 출력할 수 있습니다. 결과물에는 꽤 만족하는 편입니다. 그러나 초기 세팅 그대로 사용하면 한글 폰트가 정보가 없어 한글이 죄다 사각형으로 나옵니다. 참고로 제가 사용하는 폰트는 '조선일보 명조체'입니다.

PDF 출력

문서 웹페이지 주소에 '&do=export_pdf'를 붙여주면 PDF 파일을 다운로드 받을 수 있습니다. 'http://changwoo/doku.php?id=project:dokuwikisetting&do=export_pdf' 이렇게 말이죠. 단, 링크 주소에는 '#' 기호로 시작하는 페이지 내부 연결 링크 문자가 붙어 있으면 안 됩니다.

한글 폰트
  1. 플러그인을 받아 lib\plugins 디렉토리에 'dw2pdf'란 하위 디렉토리로 플러그인을 설치합니다.
  2. 출력되고자 하는 글꼴을 선택해서 dw2pdf/mpdf/ttfonts에 복사합니다.
  3. dw2pdf/mpdf/config_fonts.php 파일을 열어서 몇 군데를 수정해야 합니다.
    1. /* Examples of some CJK fonts */ 주석을 찾습니다.
    2. 주석된 코드와 비슷하게 이전 과정에서 복사한 폰트 파일의 앨리어스를 만들어야 합니다. 나눔고딕(nanum.ttf), 맑은고딕(malgun.ttf), 조선일보 명조(ChosumM.ttf)의 앨리어스를 만든다면,
      "nanum_gothic" => array(
      	'R' => "Nanum.ttf",
      	'B' => "Nanum.ttf",
      	'I' => "Nanum.ttf",
      	'BI' => "Nanum.ttf"
      	),	
      "malgun_gothic" => array(
      	'R' => "malgun.ttf",
      	'B' => "malgun.ttf",
      	'I' => "malgun.ttf",
      	'BI' => "malgun.ttf"
      	),	
      "chosun_m" => array(
      	'R' => "ChosunM.ttf",
      	'B' => "ChosunM.ttf",
      	'I' => "ChosunM.ttf",
      	'BI' => "ChosunM.ttf",
      	),

      가 되겠습니다.

    3. dw2pdf/mpdf/config.php 파일에서
      $this->useAdobeCJK = false

      를 확인합니다. 'true'를 사용하면 멋없는 한글 폰트가 나옵니다.

  4. dw2pdf/mpdf/config_cp.php 파일에서 CASE “ko”: 부분을 찾습니다.
    if ($adobeCJK) {
    ...
    }
    else {
        $unifonts = "chosun_m";
    }
    break;

    $unifonts 부분에 위에서 설정한 폰트의 앨리어스를 넣어주면 한글은 올바르게 나옵니다.

PDF 캐시

PDF 작성에 시간이 오래 걸리기 때문에 플러그인은 한 번 만든 PDF 파일은 문서 내용이 수정되지 않는 한 한 번 만들어진 파일을 캐싱해둡니다. 이것저것 세팅값의 변화를 빨리 체크해 볼 때는 캐시가 없는 것이 더 좋습니다. 도쿠위키의 '관리-환경설정'에 가서 'Dw2pdf 플러그인 설정' 항목에서

Should PDFs be cached? Embedded images won't be ACL checked then, disable if that's a security concern for you.

항목의 체크를 해제하면 됩니다. PDF 출력 설정이 안정적으로 된 이후에 캐시 기능을 활성화하세요.

이미지 첨부 에러

PDF 내부의 QR 코드, 혹은 이미지가 올바르게 출력되지 않는 경우가 발생할 수 있습니다. 이 경우 우선 dw2pdf/config.php에서 '$this→showImageErrors'를 찾아 true로 변경하여 이미지 처리 과정 중 발생하는 에러를 출력하여 봅니다. 제가 삽질을 할 당시에는 PHP의 GD 라이브러리를 설치하지 않아 해당 문제가 발생하였습니다.

mPDF error: IMAGE Error (D:/Server/nginx/html/data/media/project/teracopy_wnd.png): GD library required for PNG image (alpha channel)

해결 방법은 php.ini에서 extension=php_gd2.dll 주석을 해제하여 GD 라이브러리를 로딩해주면 됩니다. GD 라이브러리가 로드되었는데도 다음과 같은 에러가 발생할 수 있습니다.

mPDF error: IMAGE Error (https://chart.googleapis.com/chart?chs=120x120&cht=qr&chl=http://changwoo/doku.php?id=project:peekwindow): Could not find image file

이 경우 dw2pdf/action.php를 열어 'protected function load_template($title)'을 찾습니다. 'https' 프로토콜을 'http'로 변경합니다.

PDF 변환 시간이 오래 걸릴 때

개인 서버로 저사양의 PC를 사용하는 경우 PDF 변환에 상당한 시간을 필요로 합니다. 그런데 NginX나 Apache등에서 php에 대해 스크립트 실행 시간 제한이 있다면 이 시간 제한에 걸려 PDF를 생성하지 못하는 일이 발생할 수도 있습니다. 이 경우 타임아웃 시간에 조금 여유를 두는 것이 좋습니다.

PHP는 php.ini에서 max_execution_time을 증가시키면 됩니다.

출처: http://stackoverflow.com/questions/9629566/how-to-increase-apache-timeout-directive-in-htaccess

백업 & 동기화

백업

다음과 같은 파이썬 스크립트로 백업을 수행하도록 하였습니다. 윈도우 탐색기에서 파일을 두 번 클릭하면 동작하고, 원하시면 스케쥴러에 등록해두고 주기적으로 실행시켜도 됩니다. 드롭박스, 스카이드라이브, 구글 드라이브, 네이버 N 드라이브, 다음 클라우드등 여러 클라우드 서비스가 있습니다. 하나 골라서 PC 클라이언트를 구동시키면 클라우드에 자동 백업이 됩니다. 꽤 안심입니다. 개인적으로는 드롭박스나 스카이드라이브를 추천합니다.

BackupDokuWiki.py
# -*- coding: cp949 -*-
from zipfile import ZipFile
from datetime import date
import os
 
# 도쿠위키를 ZIP 파일로 압축
def backup_dokuwiki(saveas):	
	# root directory of dokuwiki
	DOKUWIKI_ROOT = 'D:/Server/nginx/html/'
 
	# minimum list of backup
	# https://www.dokuwiki.org/faq:backup
	DIRS_TO_BACKUP = ('conf', 'data/pages', 'data/meta', 'data/media', 'data/attic')
 
	#backup_dokuwiki	
	with ZipFile(saveas, 'w') as zf:
		oldpath = os.getcwd()
		os.chdir(DOKUWIKI_ROOT)
		for dir in DIRS_TO_BACKUP:
			path = DOKUWIKI_ROOT + dir
			for dirpath, dirnames, filenames in os.walk(path):				
				for filename in filenames:
					relpath = os.path.relpath(dirpath+'/'+filename, DOKUWIKI_ROOT)
					print relpath
					zf.write(relpath)	
		os.chdir(oldpath)
 
# 압축된 파일을 클라우드와 동기화
def moveto_cloud(filename):
	CLOUD_PATH = 'C:/Users/changwoo/Dropbox/dokuwiki/'
 
	cloud_file = CLOUD_PATH+'/'+filename
 
	if os.path.exists(cloud_file):
		os.remove(cloud_file)
 
	os.rename(filename, cloud_file)
 
def main(argv):
	today    = date.today()
	filename = today.strftime('DokuWikiBackup%Y%m%d.zip')
 
	backup_dokuwiki(filename)
	moveto_cloud(filename)
 
	return 0
 
if __name__ == '__main__':
	import sys
	sys.exit(main(sys.argv))

아래 스크립트는 zip이 아닌 tar.bz2로 압축합니다. tar를 사용하기 때문에 파일의 권한이 보존되는 장점이 있습니다. 기능은 거의 비슷하지만, 이쪽을 더 추천합니다. 아래 파이썬 스크립트는 몇 가지 기본 인자를 받아 처리하며, 인자에 따라 백업 방식이 약간 달라집니다. -a 스위치를 붙이면 도쿠위키에 대해 전체 스냅샷을 생성하며, -p 스위치를 붙이면 유저가 따로 설치한 플러그인을 추가해서 백업을 합니다. 물론 -a-p 보다 더 광범위한 옵션이기 때문에 둘이 같이 사용될 경우 -p는 무시되는 것과 마찬가지 효과가 일어납니다.

backup.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import getopt
import os
import sys
import tarfile
 
def help():
    help_msg = '''Usage: backup.py -r dokuwiki_root [-a] [-p] (filename_prefix)
       -r: dokuwiki root path
       -a: backup all dokuwiki data
       -p: backup with user plugins
       -h: print this message
 
* Backup target: conf, data/{attic, media, media_attic, meta, pages}       
* Output file name: (filename_prefix)_YYYYMMDD(state).tar.bz2
    e.g.) backup_20130719.tar.bz2   # only backup target
          backup_20130719a.tar.bz2  # all snapshot
          backup_20130719p.tar.bz2  # backup target with user-installed plugins'''
 
    print help_msg
 
def main(argv):    
    optlist, args = getopt.getopt(argv[1:], 'r:aph')
 
    # check optlist
    dokuwiki_root = None
    backup_all = False
    with_plugin = False
 
    for opt in optlist:
        if opt[0] == '-r':   dokuwiki_root = opt[1] 
        if opt[0] == '-a':   backup_all = True
        if opt[0] == '-p':   with_plugin = True
        if opt[0] == '-h':
            help()
            return 0
 
    # check args
    if len(args) != 1:
        print >> sys.stderr, 'Error in filename_prefix'
        return 1    
    file_prefix = args[0]
 
    if dokuwiki_root is None:
        print >> sys.stderr, 'dokuwiki_root not given'
        return 1
 
    backup_dokuwiki(dokuwiki_root, backup_all, with_plugin, file_prefix)
 
def backup_dokuwiki(dokuwiki_root, backup_all, with_plugin, file_prefix):
    # minimum list of backup
    # https://www.dokuwiki.org/faq:backup
    DIRS_TO_BACKUP = ('conf', 'data/attic', 'data/media', 'data/media_attic', 'data/meta', 'data/pages')
    DEFAULT_PLUGIN = set(['acl', 'authad', 'authldap', 'authmysql', 'authpgsql', 'authplain', 'config', 'info', 'plugin', 'popularity', 'revert', 'safefnrecode', 'testing' , 'usermanager'])
    PLUGIN_PATH_PREFIX = 'lib/plugins'
 
    statecode = ''    
    if backup_all:
        statecode = 'a'
    elif with_plugin:
        statecode = 'p'
 
    datetimestr = datetime.datetime.strftime(datetime.datetime.now(), '%Y%m%d')
    filename = '%s_%s%s.tar.bz2' % (file_prefix, datetimestr, statecode)
 
    oldpath = os.getcwd()
    os.chdir(dokuwiki_root)
    tar = tarfile.open(filename, 'w:bz2')    
    if backup_all:
        tar.add('./')    
    else:
        for dir in DIRS_TO_BACKUP:            
            tar.add('./' + dir)
 
        # plugin
        if with_plugin:            
 
            for dir in os.listdir(PLUGIN_PATH_PREFIX):
                path = os.path.join(PLUGIN_PATH_PREFIX, dir)
                isdefault = dir in DEFAULT_PLUGIN
 
                # only archive user-install plugins                
                if os.path.isdir(path) and not isdefault:
                    tar.add('./'+path)
 
    os.chdir(oldpath)    
    tar.close()    
 
    print filename
 
    return 0
 
if __name__ == '__main__':
	sys.exit(main(sys.argv))

위 파이썬 코드는 단지 압축 파일을 생성할 뿐입니다. 이렇게 생성된 파일은 클라우드 서비스 같은 원격지에 따로 보관하면 더욱 안정적으로 데이터를 보관할 수 있을 것입니다. 아래 bash 쉘 스크립트는 자동으로 보통 옵션(conf, data 디렉토리 주요 내용)으로 위키 데이터를 백업한 후, skydrive-cli를 이용하여 skydrive에 파일을 올립니다.

autobackup
#!/bin/bash
 
# requirement
# Python 2.7
# https://github.com/mk-fg/python-skydrive
#
# pip install 'python-skydrive[standalone]'
# pip install pyyaml requests
#
# https://manage.dev.live.com/
# put yaml file: ~/.lcrc
# client:
#  id: 00000000440EB189
#  secret: JbWpwkOA4bp3jYBCG5wWLb6fqWJHLSkc
#
# ATTENTION: above id/secret is real!! Do not distribute!!
# skydrive-cli auth
 
SCRIPT_ROOT=/home/changwoo/scripts
DOKUWIKI_ROOT=/home/changwoo/public_html/dokuwiki
FILE_PREFIX=/home/changwoo/DokuWikiBackup
SKYDRIVE_PATH=DokuWikiBackup
 
echo "Backup Dokuwiki..."
BACKUPFILE=`python $SCRIPT_ROOT/backup.py -r $DOKUWIKI_ROOT $FILE_PREFIX` 
 
echo "Upload to SkyDrive..."
/usr/local/bin/skydrive-cli put $BACKUPFILE $SKYDRIVE_PATH # CHECK THE PATH!
 
echo "Removing...$BACKUPFILE"
rm -f $BACKUPFILE

이 스크립트를 서버에서는 3일마다 한 번씩 동작시킵니다.

$ crontab -e

편집기에 다음처럼 스크립트를 추가합니다. 3일에 한 번 오후 6시 정각에 autobackup 스크립트를 동작시킵니다.

00 18 */3 * * <PATH_SCRIPT_IS>/autobackup > /dev/null

동기화

복잡한 동기화는 아직 생각해 보지 않았습니다. 스마트폰, 태블릿, PC 이곳저곳에서 다 사용가능한 시스템은 좀 호들갑스럽지 않나 생각이 듭니다. 현재 저는 인터넷 환경이 그다지 편하지 않은 곳에서도 안정적으로 글을 쓸 수 있는 로컬 서버 형태를 더 선호합니다. 물론 NAS나 개인 서버가 가능하신 분들이라면 동기화 문제는 이미 해결된 셈이네요. 개인적인 의견입니다만, 스마트폰이나 태블릿으로 위키 쓰기는 너무 실험적인 일인 것 같습니다. :-/

한 대의 PC만 사용한다면 동기화에 대해 그렇게 복잡하게 생각할 필요가 없으나, 요즘 2대 이상 여러 기계를 사용하는 경우가 많아졌습니다. 위키를 NAS와 같은 관리하기도 안정적이고 어디서나 접근 가능한 곳에 보관한다면 좋겠지만 그렇지 않은 경우에는 개인 위키의 데이터 백업도 상당히 신경쓰이는 일입니다. 그래도 요즘은 dropbox와 같은 클라우드 서비스가 있으니 아카이브로 만든 파일을 dropbox를 통해 보관하면 상당히 안정적이면서도 손쉽게 데이터를 관리할 수 있습니다.

2013년 7월 현재 라즈베리 파이를 이용한 리눅스 서버에서 개인 위키를 운영중입니다. 라즈베리 파이 시작하기

비트토렌트 싱크를 이용한 싱크도 참고할 수 있습니다. 라즈베리 파이에서 BitTorrentSync로 데이터 동기화하기

RSync 를 이용한 동기화

참고 문서: rsync

리눅스 데스크탑에서 대략 1시간 간격으로 계속 업데이트를 하는 경우 이렇게 한다. 우선 미니서버에 암호 없이 들어갈 수 있도록 키를 넘긴다. 그리고 다음과 같은 쉘 스트립트를 작성한다.

dokuwiki_rsync
#!/bin/bash
 
RSYNC=/usr/bin/rsync
OPT="--verbose --recursive --update --delete"
LOCAL=/home/changwoo/public_html/dokuwiki/
REMOTE=changwoo@MiniServer:/home/changwoo/public_html/dokuwiki/
 
echo "LOCAL >> REMOTE"
$RSYNC $OPT $LOCAL $REMOTE
 
echo "REMOTE >> LOCAL"
$RSYNC $OPT $REMOTE $LOCAL

미니서버와 데스크탑의 사용자와 그룹이 사실상 같으므로 소유권과 소유자 정보를 같게 맞춰 주는 것이 무엇보다 중요하다. 관리에 상당히 문제가 있는 관계로, make_ready.sh의 쉘 스크립트의 권한을 777로 변경하였다. 또한 설정에서 디렉토리와 파일의 생성 시 권한도 777로 줬다. 어떤 한 곳의 안정적인 서버를 가지고 운영하는 거라면 이런 일이 없을 텐데

개인 도메인 설정하기 (host 파일 편집)

멋진 위키가 생겼는데 웹브라우저에 'localhost'라고 치기에는 너무 초라합니다. 오직 내 PC만 사용가능하더라도 서버의 도메인 이름을 지어 주는 것이 좋지 않을까요? :-) C:\Windows\System32\Drivers\etc 디렉토리에 'hosts'라는 파일을 텍스트 편집기로 열어 봅니다. 관리자 권한으로 파일을 열어야 편집이 가능한 점 잊지 마세요.

아래와 같은 내용이 있을 것입니다.

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost

여기에 다음과 같이 내용을 추가합니다.

# My Server setting
	127.0.0.1       changwoo
	::1             changwoo

이제 'changwoo'라는 도메인은 127.0.0.1의 IP 주소는 가리킵니다. 이 host 파일이 있는 PC 안에서만 유효한 것입니다만, 그래도 localhost보다는 낫다고 생각합니다. 제 PDF 문서에 보이는 URL 주소에 'http://changwoo'라는 듣도 보도 못한 이상한 도메인 이름이 적힌 것은 이렇게 저만의 도메인을 사용했었기 때문입니다. '.co.kr'이나 '.com' 같은 접미사는 굳이 쓰지 않아도 되는 것 아시지요?

마치며

모든 설정이 끝난 제 현재 위키의 스크린샷입니다. 본 문서네요. :-) 템플릿을 변경하여 미디어위키의 'vector' 스타일로 변경해 보았습니다. 왼쪽 메뉴에 PDF 및 출력용 메뉴가 마음에 들어 사용하고 있습니다.

지금까지 제 개인 PC에 개인용으로 사용중인 도쿠위키의 세팅을 문서화해 보았습니다. 일종의 dog feeding인가요? :-) 개인적으로 위키를 사용해보면서 느낀 소감은 이렇습니다. 머릿속의 지식을 명확하게 정리해 문서화하여 가시화해두니 꾸준히 무언가 쌓여가는 느낌이 듭니다. 위키를 설치해서 꾸준히 내용을 적어가기 시작한 건 참 잘 한 일이라고 생각합니다. 위키를 작성하는데 꽤 시간과 노력이 들지만, 지식이 체계적으로 정리되는 것도 좋고, 잘 만들어진 문서를 보면 별 거 없는데도 뿌듯합니다. 글쓰기 연습도 되고 있구요.

이 글을 보고 '나도 해 볼까? PC에 위키 설치해 봐?'라고 마음먹으셨다면 정말 해 보시길 권합니다. 조금씩 조금씩 글을 적어 나가다보면 결국 만족스러운 자신만의 저널이 탄생하게 되겠죠.

1)
PDF로 변환할 때 두번째 location의 괄호 안 문자에 의도하지 않은 오타가 섞이는 버그가 있습니다. 정확한 코드는 다음과 같습니다.
location @dokuwiki {
rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
rewrite ^/(.*) /doku.php?id=$1 last;
}