원래는 따로 글을 써서 정리할까 했는데 GitHub wiki에 워낙 잘 정리되어 있어서 링크로만 소개하고자 한다.

  1. Generating SSH keys
  2. Changing a remote’s URL

SSH 키 세팅하고 나서 remote URL을 https로 시작하는 주소가 아니라 git으로 시작하는 주소로 설정해 주면 된다. 매 번 ID와 패스워드를 입력할 필요가 없기 때문에 편리하게 사용하고 있다.

2부에서는 DB 설치 및 Django 세팅을 다룰 예정이다. PostgreSQL 9.3.8, Django 1.8.2 버전을 기준으로 작성했다. 작성하면서 Digital Ocean의 튜토리얼을 참고했다.

1. DB 설치 및 접속

  1. sudo apt-get install postgresql postgresql-contrib로 postgresql를 설치한다.
  2. virtualenv에 pip install psycopg2로 PostgreSQL 파이썬 커넥터를 설치한다. 오류가 발생하는 경우 apt-get으로 libpq-dev 패키지를 설치한다.
  3. sudo -u postgres psql로 SQL 환경을 시작할 수 있다.

유용한 명령어들

  • \? 명령어 도움말을 보여준다.
  • \l 데이터베이스 목록을 보여준다.
  • \dt 테이블 목록을 보여준다.
  • \dg 유저 목록을 보여준다.
  • \c DATABASE_NAME 데이터베이스에 접속
  • \q SQL Environment 종료

template database

PostgreSQL을 설치하면 기본적으로 postgres, template0, template1 데이터베이스가 있다. PostgreSQL에서는 데이터베이스를 만들 때 기본적으로 template1을 복제해서 만들어지기 때문에 여기에 모든 데이터베이스에 적용할 확장 기능을 설치하는 식으로 이용한다. template0은 데이터베이스 초기의 순수한 상태 템플릿으로 이용하며, template0을 복제할 때는 DB의 인코딩이나 locale을 세팅할 수 있다.

2. 사용자 계정 생성

  1. CREATE DATABASE toytest;로 toytest 데이터베이스 생성. #
  2. CREATE USER toytest with PASSWORD 'password';로 계정 생성. 패스워드는 랜덤 제너레이터를 사용했다. #
  3. GRANT ALL PRIVILEGES ON DATABASE toytest TO toytest;로 toytest DB에 대한 권한을 toytest Role에 할당한다.

3. Django 세팅 파일 수정

Django를 VCS로 관리할 때 비밀 정보들이나 사이트마다 다른 로컬 세팅들은 VCS에 포함해서는 안 된다. 이런 정보들은 local_settings.py에 옮겨서 저장하자.

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'SECRET_KEY'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['toytest.qwaz.io',]

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'toytest',
        'USER': 'toytest',
        'PASSWORD': 'PASSWORD',
        'HOST': 'localhost',
        'PORT': '', # default port
    }
}

PostgreSQL의 기본 포트는 5432고, 기본 포트를 사용하는 경우 비워 놓아도 된다.

settings.py에서는 겹치는 설정을 제거해주고 LANGUAGE_CODE와 TIME_ZONE을 수정한다. LANGUAGE_CODE는 프로젝트 성격에 따라 en-us 또는 ko-kr로 설정하고, TIME_ZONE은 서버가 있는 Asia/Tokyo로 설정해 주자.

설정을 마치고 settings.py에 from .local_settings import *를 추가한다.

수정한 프로젝트를 다시 읽어오기 위해서는 여러가지 방법이 있는데 touch toytest_uwsgi.ini가 가장 편리하다. Emperor Mode로 uWSGi를 실행시켜두었기 때문에 ini 파일의 수정을 감지해 uWSGI가 다시 로드된다.

DB 연결이 끝나면 python manage.py migrate를 실행해 데이터베이스 연결이 잘 되었나 확인한다.

동기

최근 도메인을 산 김에 토이 프로젝트로 요즘 유행하는 익명 질답 서비스를 간단하게 만들어보려고 했다. Bitnami에서 클릭 몇 번으로 스택을 구성할 수 있는 것처럼 보여서 AWS 프리 티어랑 합쳐서 두 세 시간 정도 삽질을 했다. 무료 티어에서는 micro급 EC2 인스턴스를 무료로 제공해 주는데, Auto Scaling이 필요한 수준은 돼야 AWS의 장점을 느낄 수 있을 것 같고 이 정도로는 다른 VPS랑 비교해서 딱히 장점이 느껴지지 않았다. 그래서 차라리 오래 쓸 목적으로 싸고 적당한 VPS 하나를 맞추고자 가상서버 호스팅 비교글을 보고 가격 대비 트래픽과 하드 용량이 좋은 ConoHa에서 제일 싼 서버를 하나 맞췄다.

예전에 학교 서버에서 급식 평가 사이트 돌릴 때 서버 세팅에서 삽질을 많이 했었기 때문에 이번에는 세팅하면서 삽질 과정을 포스팅에 메모해 놓기로 했다. 서버 첫 설치부터 시작해서 삽질의 과정을 내가 나중에 다시 보면 기억날 수준으로만 간단하게 정리해 보았다. nginx + Django + uWSGI로 디플로이 할 일이 제일 많을 것 같아서 이 세팅으로 저장해 두었고, 사용하는 프레임워크 따라 적절히 변경해서 사용하면 된다. 작성하면서 이 글을 참고했다.

1. 설치

처음 설치하고 나서 root 계정으로 필요한 것들을 깔아준다. Ubuntu 14.04 기준이고 대부분의 작업에 python3를 사용한다.

$ apt-get update
$ apt-get upgrade
$ apt-get install build-essential zsh git python3-dev python3-pip nginx lrzsz
$ pip3 install virtualenv

2. SSH 키 생성하기

  1. useradd qwaz로 유저를 추가한다.
  2. groupadd admin으로 어드민 그룹 생성.
  3. usermod -a -G admin qwaz로 유저를 어드민 그룹에 추가.
  4. login qwaz로 로그인 후 sudo 되는지 테스트.
  5. XShell 등에서 사용자 키를 생성하고 공개키를 .ssh/authorized_keys 위치에 업로드한다. 디렉터리가 없는 경우 생성하고 권한은 700으로 준다.
  6. 로그아웃 후 Key 사용해서 로그인 되는지 테스트.

3. zsh 세팅하기

  1. curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh로 oh-my-zsh 설치
  2. chsh -s /bin/zsh로 기본 셸을 zsh로 변경 후 터미널 재접속.
  3. .zshrc를 수정해 테마나 플러그인을 취향대로 변경. bullet-train이 괜찮더라.

4. virtualenv 세팅

개발용 계정은 하나를 쓰고 projects 디렉터리 내부에 개발하는 프로젝트를 관리할 것이다. 프로젝트마다 계정을 생성해도 되는데 개인적으로는 이 방식이 편하게 느껴진다.

프로젝트 디렉터리가 없는 경우 mkdir projects로 생성하고 ~/projects 디렉터리로 이동한다.

toytest라는 프로젝트를 예시로 진행해보겠다.

$ virtualenv toytest
$ cd toytest
$ source bin/activate
$ pip install django
$ cd django

virtualenv toytest로 가상 환경을 만든다. 이렇게 만든 가상환경은 source toytest/bin/activate로 활성화하고 deactivate로 비활성화 할 수 있다.

virtualenv를 켜기 전에는 파이썬 버전에 따라 pip, pip3로 명령어가 다르지만 virtualenv를 python3로 설치했기 때문에 활성화 후에는 그냥 pip 명령어만 입력해도 python3 버전으로 작업할 수 있다. pip가 사용중인 파이썬 버전은 pip -V로 확인할 수 있다.

5. Django 프로젝트 생성

서버에서 바로 django-admin startproject toytest로 시작해도 되고, 로컬에서 생성한 뒤 git clone 등을 이용해 가져오게 설정해도 된다. 과정은 거의 동일하기 때문에 서버에서 바로 생성하는 방법으로 설명하겠다.

~/projects/toytest 디렉터리에서 django-admin startproject toytest 명령으로 toytest 프로젝트를 시작하자.

6. nginx 세팅

생성한 Django 프로젝트를 수정하기 전에, ~/projects/toytest에 로그나 소켓 등을 먼저 설정한다.

$ mkdir misc log
$ cd log
$ touch access.log error.log toytest.log
$ cd ..
$ cd misc

misc 디렉터리에 toytest_nginx.conf를 만들고 다음과 같은 내용을 추가하자.

server {
        # the port your site will be served on
        listen 80;

        # the domain name it will serve for
        server_name     toytest.qwaz.io;
        charset         utf-8;

        access_log      /home/qwaz/projects/toytest/log/access.log;
        error_log       /home/qwaz/projects/toytest/log/error.log;

        location / {
                include /etc/nginx/uwsgi_params;
                uwsgi_pass unix:///home/qwaz/projects/toytest/misc/toytest.sock;
        }
}

이 파일을 symlink로 nginx 디렉터리에 추가한다.
sudo ln -s ~/projects/toytest/misc/toytest_nginx.conf /etc/nginx/sites-enabled/

7. uWSGI 세팅

여기를 참고했다.

우선 virtualenv를 잠시 꺼두고, pip3로 uWSGI를 system-wide로 설치한다.

$ deactivate
$ sudo pip3 install uwsgi

virtualenv를 다시 켜고 python manage.py runserver 0.0.0.0:8000로 Django를 돌려보자. 웹브라우저에서 toytest.qwaz.io:8000로 접속해 접속이 되는지 테스트 해본다.

잘 동작했다면 이번에는 uwsgi --http :8000 --module toytest.wsgi -H ~/projects/toytest로 uWSGI를 사용해 다시 한 번 테스트 해본다.

여기까지 성공했다면 이제 아래 toytest_uwsgi.ini파일을 misc 폴더에 만들자. 설정 파일 만들 때는 여기를 참고했다.

[uwsgi]

# Django-related
chdir           = /home/qwaz/projects/toytest/toytest
module          = toytest.wsgi

# virtualenv
home            = /home/qwaz/projects/toytest

# process-related
master          = true
processes       = 8

# permission
uid             = qwaz
gid             = www-data

# misc files
socket          = /home/qwaz/projects/toytest/misc/toytest.sock
chmod-socket    = 664
pidfile         = /home/qwaz/projects/toytest/misc/toytest.pid
daemonize       = /home/qwaz/projects/toytest/log/toytest.log

harakiri        = 60
max-requests    = 4096
reload-on-as    = 512
reload-on-rss   = 192
limit-as        = 1024

no-orphans      = true
vacuum          = true

uwsgi --ini toytest_uwsgi.ini로 uwsgi를 실행시키고 sudo service nginx restart로 추가한 sites-enabled를 읽도록 nginx를 재시작하고 브라우저로 접속해보자. 접속에 성공했다면 sudo kill -9 $(cat /home/qwaz/projects/toytest/misc/toytest.pid)로 프로세스를 죽인다.

8. Emperor Mode

웹서버 관련 설정은 거의 다 끝났다. 이제 uWSGI를 Emperor Mode로 실행시키고 서버가 시작했을 때 자동으로 실행되도록 만들어주자. Emperor Mode에서는 ini 파일이 변경될 때마다 새로운 인스턴스를 띄워준다.

sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
sudo ln -s /home/qwaz/projects/toytest/misc/toytest_uwsgi.ini /etc/uwsgi/vassals/
sudo uwsgi --emperor /etc/uwsgi/vassals --uid qwaz --gid www-data

실행 되는 것을 확인했다면 프로세스를 종료하고, 마지막으로 서버가 켜질 때 uWSGI가 뜨도록 해 보자.

/etc/rc.local 파일을 열어 /usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid qwaz --gid www-data를 추가하고 서버를 재부팅해서 사이트가 뜨는지 확인한다.

여기까지 마치면 디렉터리 구조는 다음과 같이 된다.

~/
└ projects/
  └ toytest/
    ├ (virtualenv 관련 파일들)
    ├ log/
    │├ access.log
    │├ error.log
    │└ toytest.log
    ├ misc/
    │├ toytest_nginx.conf
    │└ toytest_uwsgi.ini
    └ toytest/
      ├ manage.py
      └ toytest/
        ├ settings.py
        ├ urls.py
        └ wsgi.py

몇 부까지 있을지는 모르겠지만 다음에는 DB 세팅과 Django 세팅 파일 설정 등을 건드릴 예정이다.

원래는 블로그 도메인으로 .dev를 구매하려고 풀리는 것을 기다리고 있었다. 2014년 말에 공개될 예정이라고 알고 있었는데 좀처럼 공개되지 않길래 좀 더 알아보니 구글이 사용 권리를 구매하고 대중 공개를 하지 않고 있었다. # 구글 사내 모토가 Don’t be Evil이라고 알고 있었는데 다 옛날 얘기인 듯하다.

.dev 도메인이 더 끌렸지만, 기다려서 해결될 문제가 아니라고 생각되어 차선책인 .io 도메인을 구입했다. Gandi와 NameCheap 중 어디서 살지 고민하다가 NameCheap이 UI가 좋길래 거기서 구매했다. 구매하는 김에 SSL도 초기 1년 분을 싸게 팔길래 같이 사 보았다.

구매할 때까지는 큰 어려움이 없었는데 구매하고 나서는 이것저것 설정해 줄 게 많은데 처음 해 보는 작업이라 고생했다. 특히 cafe24에서 도메인을 연결하고 싶으면 자기들 네임서버에 등록하는 것을 기본 절차로 제시하고 있는데, cafe24에서 직접 구매한 도메인이 아니면 관리 기능이 많이 부실하고 내가 사용하는 절약형에서는 서브 도메인으로 연결하는 것이 불가능하고 메일 포워딩 등의 추가 기능도 제공하지 않아 다시 NameCheap으로 돌아왔다. 어떻게 해야 되나 고민하던 차에, 고객센터에 문의를 넣으면 해결해 준다는 글을 발견하고 문의를 했더니 반나절만에 처리되어 네임서버는 NameCheap에서 사용하면서 서브도메인 blog.qwaz.io로 cafe24 호스팅에 연결할 수 있었다.

다음 문제는 SSL 인증서를 활성화 하는 단계에서 발생했다. 처음에 인증서 받을 활성화 메일 선택을 잘못 해서 인증서가 PURCHASEERROR 상태로 굳어버린 것이다. 시험 기간이라 바빠서 건드리지 못하고 있다가 오늘 시험이 끝나고 나서 NameCheap 고객센터에 문의를 넣어 보았다. 무려 24시간 실시간 채팅을 할 수 있는 분야별 상담원이 대기하고 있었다(!) 처음에는 영어로 내 상황을 잘 설명하지 못할 것 같다고 걱정했는데 의외로 술술 채팅이 풀리고, 상담원이 활성화할 수 있게 문제를 해결해 주어서 SSL 인증서를 발급 받는데 성공했다. 지금은 cafe24에 인증서 등록해 놓고 적용되기를 기다리고 있는 중이다.

도메인 적용하고 나면 URL이 바뀌니까 구매하고 나서 블로그 공개하려고 검색엔진도 막고 공유도 안 하고 있었다. 그래서 네이버 블로그에서 이사한 뒤로 한동안 블로그에 혼잣말만 쓰고 있었는데 이제는 블로그에 쓴 글도 SNS에 공유할 수 있다! 더불어 URL이 과거의 못생긴 *.cafe24.com에서 예쁜 URL로 바뀌어서 기분이 굉장히 좋다.