これまではxreaを使っていました。なんといっても安い。(My|Postgre)SQLがバックエンドにデフォルトで用意されていて、テキトーに小さなサーバーがほぼDedicatedでvirtualhostか何かで共有されているのでもよいと思っていました。
でも許せなかったんです。手元ではPython 2.6, PostgreSQL 9.0.1という割と新しい環境なのに、サーバー側はPython 2.4, PostgreSQL 8.4何とかとかいう古い環境。既に手元でDjangoの開発終わってしまいマシタヨー。いくら私にはbuildoutがついているッ!!といったところでこの二つばかりはbuildoutでもどうにもなりません。
以前自宅にサーバーがあった頃は、引越しでサーバー止めないといけないとかそういう緊急事態にAWSでサーバー起こして1週間だけ運用とかやったんですよ。でも高い。xreaがこみこみで月500円くらいなのに、AWSと来たらなんだかんだで7000円くらいとりやがる。そりゃあmicro instanceもなかった頃だし、海の向こうのDCだし*1、これで商売しようとする人間には初期投資がないだけでも十分うれしい価格(メンテだけでこんくらい飛んでいくもんねー)だわさ。でもインターネットは基本無料だと思っている私です。接続会社とプロバイダ以外にお金を払う気がないです(ぉ
そこでxreaやめてさくらのVPS使ってみることにしたんです。月1000円くらい。環境については
- Pros
- ブラウザからコンソールが使える
- 起動とか再インストールとか簡単
- DedicatedなOSが使える!!
- コントロールパネルかっこいい
- Cons
といったところで、とてもよいと思います。sshで入っても長時間走ってるプロセスはkillされるとかいうのよりはるかにすばらしい*2。
CentOSが古いので、昔のようにサーバーを手作りしないといけません。PostgreSQL 9.0.1をソースからとってきて何も考えずに
$ tar xvzf postgreql-9.0.1.tar.gz -C /usr/src/mines
$ cd /usr/src/postgresql-9.0.1
$ ./configure
$ make
# make install
そうすると/usr/local/pgsqlイカに一式入るんだけど、binがPATHに入らないわlibがコンパイラとかリンカに入らないわまー大変。/etc/ld.so.conf.d/postgresql.confに/usr/local/pgsql/libと一行かいて# ldconfig とかやるんです。いまどきこんなことやるなんて思わなかった。あ、その前にpsycopg2のインストールに苦戦したりとかね。libpq-fe.hがねーよとか言われるんです。でドキュメントとか読んでられないのでググッた−
# python setup.py build_ext --pg-config /path/to/pg_config build
# python setup.py install
Pythonは、djangoが動くから2.4のままでいっかぁーと。ふつうにインストールしました。ホントはgunicornとか試せるとカッコいいなぁーとか思ったが、そんなに頑張るところでもないのでapache htttpd+mod_pythonで済ませました。/etc/httpd/httpd.confとかひさしぶりにさわったよ。あとapache httpdをちゃんとprefork MPMで動かすには…とかそういうことも調べました。preforkなはずなのになんかモッサリしてるんだよなぁ。なんでだろう。preforkでもmod_pythonでプロセス動かしたりしているのか、それとも純粋にサーバースペックが足りなくてダメなのかな。手間をかけないことを重視したのでmemcachedもそういえば入れてない。
おまけ
xreaだったころはdjango動かすためにdjango.cgiとか入れてた。毎回プロセスたちあげてたから遅かったわー
#!/usr/bin/env python # encoding: utf-8 """ django.cgi A simple cgi script which uses the django WSGI to serve requests. Code copy/pasted from PEP-0333 and then tweaked to serve django. http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side This script assumes django is on your sys.path, and that your site code is at /home/mycode/mysite. Copy this script into your cgi-bin directory (or do whatever you need to to make a cgi script executable on your system), and then update the paths at the bottom of this file to suit your site. This is probably the slowest way to serve django pages, as the python interpreter, the django code-base and your site code has to be loaded every time a request is served. FCGI and mod_python solve this problem, use them if you can. In order to speed things up it may be worth experimenting with running uncompressed zips on the sys.path for django and the site code, as this can be (theorectically) faster. See PEP-0273 (specifically Benchmarks). http://www.python.org/dev/peps/pep-0273/ Make sure all python files are compiled in your code base. See http://docs.python.org/lib/module-compileall.html """ import os, sys sys.path.append('/virtual/kuenishi/python/lib/python') # insert a sys.path.append("whatever") in here if django is not # on your sys.path. import django.core.handlers.wsgi def run_with_cgi(application): environ = dict(os.environ.items()) environ['PATH_INFO'] = environ.get('PATH_INFO', "/") environ['wsgi.input'] = sys.stdin environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1,0) environ['wsgi.multithread'] = False environ['wsgi.multiprocess'] = True environ['wsgi.run_once'] = True if environ.get('HTTPS','off') in ('on','1'): environ['wsgi.url_scheme'] = 'https' else: environ['wsgi.url_scheme'] = 'http' headers_set = [] headers_sent = [] def write(data): if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set sys.stdout.write('Status: %s\r\n' % status) for header in response_headers: sys.stdout.write('%s: %s\r\n' % header) sys.stdout.write('\r\n') sys.stdout.write(data) sys.stdout.flush() def start_response(status,response_headers,exc_info=None): if exc_info: try: if headers_sent: # Re-raise original exception if headers sent raise exc_info[0], exc_info[1], exc_info[2] finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!") headers_set[:] = [status,response_headers] return write result = application(environ, start_response) try: for data in result: if data: # don't send headers until body appears write(data) if not headers_sent: write('') # send headers now if body was empty finally: if hasattr(result,'close'): result.close() # Change this to the directory above your site code. sys.path.append("/virtual/kuenishi/python/lib/python2.4/site-packages") # Change mysite to the name of your site package os.environ['DJANGO_SETTINGS_MODULE'] = 'mywebapp.settings' run_with_cgi(django.core.handlers.wsgi.WSGIHandler())