Skip to main content

Хостинг WSGI з nic.ua

26-го листопада я отримав повідомлення від nic.ua, в якому йшла мова про можливість замовлення будь-яких послуг за половину вартості. nic.ua є реєстратором доменних імен, а після об’єднання з hosted.ua також надає послуги хостингу.

Я вже давно шукав місце для свого локального django проекту, тому вирішив взяти в оренду хостинг з тарифом NIC•1. Про те, що Python можна використовувати в режимі WSGI, я спочатку прочитав у їхній базі знань, а потім власноручно перевірив модуль mod_wsgi на сервері, що обслуговує цей блог.

Хостинг працює на базі cPanel/WHM. Донедавна я користувався тільки VPS-рішеннями і все звик налаштовувати самостійно, тому з cPanel я зустрівся вперше саме при переїзді блогу.

В ідеалі встановлення модулів Python на сервер здійснюється через віддалене з’єднання SSH. nic.ua надає доступ по SSH, про це заявлено у “додаткових послугах”. Я поцікавився умовами в службі підтримки:

SSH доступ надається в ручному режимі. Необхідні:

  • Скан-копія вашого паспорту (перші 2 розвороти)

  • Ваша статична IP адреса, з якої ви працюєте з хостингом.

  • Логін хостингу.

  • Поповнення особового рахунку на 40₴. та повідомлення номера сплаченого рахунку. Ці гроші буде списано бухгалтерією.

Послуга надається 1 раз на весь час дії хостингу.

Я вирішив для початку відтворити віддалену систему вдома на віртуальній машині, зібрати всі необхідні модулі та замовляти SSH доступ тільки якщо зібрані бінарні модулі відмовляться працювати. Все ПЗ в автоматичному режимі встановлює cPanel, проте я не бажав поки що мати з нею справу на своєму сервері. До того ж, cPanel потребує ліцензії.

Отже, на призначеному мені сервері було встановлено:

  • CentOS 6.3 x86_64

  • Apache 2.2.23 (стандартно в CentOS 6.3, але перезібраний в /usr/local)

  • Python 2.7.3, встановлений до /opt (в /usr живе python 2.6.6)

  • setuptools і virtualenv вже встановлені

  • mod_wsgi 3.3, зібраний з python 2.7.3

  • nginx 1.2.4, що проксює всі запити до Apache та віддає статичні файли

  • PostgreSQL 8.4.13 (в CentOS 6.3)

Після інсталяції CentOS 6.3 у мінімальній конфігурації я додав необхідні пакети:

yum groupinstall "Development tools"
yum install httpd-devel
yum install postgresql-devel

Для початку я зібрав Python (список пакетів для встановлення взяв з How to install Python 2.7.3 on CentOS 6.2, тому що з системами RPM не працював з 2006 року). При конфігуруванні треба вказати:

./configure --prefix=/opt/python2.7 --with-threads --enable-shared

Потім зібрав mod_wsgi, вказавши шлях до python в /opt/python2.7/bin/python. При цьому в /etc/httpd/conf.d/mod_wsgi.conf додав шлях, куди треба складати сокети:

LoadModule wsgi_module modules/mod_wsgi.so
WSGISocketPrefix run/

Далі створив віртуальний хост для test.staging.lappyfamily.net, в інсталяцію нового Python додав setuptools, через easy_install встановив virtualenv.

На сервері з повним доступом модулі можна встановлювати в системні директорії, однак, якщо це не є можливим, то можна використати virtualenv.

Подальші дії вже проводив від імені звичайного користувача.

Створив новий virtualenv у своєму каталозі та, активувавши нове оточення, додав pysocpg2 та django через easy_install. Після цього створив новий простий django проект.

Для того, щоб проект зміг знайти модулі, що були встановлені у virtualenv, в WSGI скрипті вказав наступне:

import site
site.addsitedir('/home/lappyfam/virtualenv/lib/python2.7/site-packages')
site.removeduppaths()

lappyfam – це ім’я мого користувача.

Після того, як мій додаток був готовий та коректно працював локально, я заархівував створені директорії в tar.gz (тому що у віртуальному середовищі є символічні посилання, які не можна створити через FTP) і розпакував його через файловий менеджер у веб-інтерфейсі cPanel.

Проект запрацював.

/galleries/dropbox/tln-main.png

Активація

У стандартній конфігурації WSGI працює під тим самим обліковим записом, що і apache. У статті про те, як використовувати django, сказано, що для активації проекту потрібно подати заявку до служби підтримки.

Активацією в nic.ua називається додавання наступних рядків до конфігурації віртуального хосту:

GIScriptAlias / /path/to/wsgi.py
WSGIDaemonProcess $PROJECT_NAME user=$USER group=$GROUP processes=2 threads=1 display-name=%{GROUP}
WSGIProcessGroup $PROJECT_NAME
WSGIApplicationGroup %{GLOBAL}

Після цього процес WSGI буде працювати через обліковий запис користувача. Хочу наголосити, що додавати Alias для статичних файлів не потрібно, запит спочатку обробляє nginx, який самостійно перевіряє DOCUMENT_ROOT на наявність потрібних файлів.

Якщо використовується WSGIScriptAlias в кореневій директорії, то .htaccess буде ігноруватися. Служба підтримки пішла назустріч та прибрала рядок WSGIScriptAlias з конфігурації. В такому разі wsgi скрипт має знаходитися в DOCUMENT_ROOT, а в .htaccess буде щось на кшталт:

Options +ExecCGI
RewriteEngine On
AddHandler wsgi-script .wsgi

# Prefer django.wsgi not to be visible
RewriteRule ^django.wsgi$ / [R,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /django.wsgi/$1

Basic/Digest Auth

Якщо використовувати wsgi через RewriteRule без WSGIScriptAlias, то django не буде коректно працювати з Basic або Digest Auth, тому що RemoteUserMiddleware не буде отримувати змінну REMOTE_USER (якщо авторизація була, наприклад, у папці /api, а сам WSGI скрипт розміщено у корені). При цьому буде передаватися змінна REDIRECT_REMOTE_USER, яку django не використовує.

Для того, щоб django використовував нову змінну, потрібно створити нове Middleware:

from django.contrib.auth.middleware import RemoteUserMiddleware

class RedirectRemoteUserMiddleware(RemoteUserMiddleware):
    header = 'REDIRECT_REMOTE_USER'

База даних

Для того, щоб мати змогу робити резервну копію бд локально та проводити міграції структури напряму через django-admin, я надіслав до служби підтримки запит з обґрунтуванням потреби доступу до бази даних, і через 4 години доступ було надано. Ця послуга є безкоштовною, але клієнтові необхідно мати статичну адресу. Тут є стаття про MySQL, але для PostgreSQL умови не відрізняються.

Якщо PostgreSQL відмовляється надавати доступ через localhost, потрібно використовувати адресу 127.0.0.1, тому що localhost веде до IPv6 адреси ::1. Я повідомив службу підтримки про цю ситуацію, і протягом декількох хвилин необхідні зміни конфігурації вже було внесено.

Пошта

Локальний сервер відмовляється надсилати пошту, якщо не існує локального користувача, що вказується як адресант. Для того, щоб мій додаток зміг надіслати листа, потрібно створити локальну поштову скриньку або переадресовувати пошту на іншу.

Якщо цього не зробити, то віддалений сервер (наприклад GMail або Яндекс) не зможе підтвердити наявність облікового запису та відповість:

{'recipient@example.net':
(550, 'Verification failed for \nNo Such User Here"\nSender verify failed')}

DKIM

В cPanel можна увімкнути підтримку DKIM. Незважаючи на те, що текст у довідці натякає тільки на підтримку перевірки вхідної кореспонденції, це налаштування керує підписуванням вихідних листів. Для того, щоб необхідні заголовки DKIM були додані до листів, останні потрібно надсилати через локальний SMTP сервер. Використання sendmail напряму не підходить (це стосується тільки сторонніх скриптів, django не використовує sendmail).

Приватний та публічний ключі створюються автоматично і їх не можна змінити або побачити через cPanel. Оскільки мій домен зареєстрований і підтримується у GoDaddy, то мені потрібно було лише видобути публічний ключ:

$ dig TXT default._domainkey.lappyfamily.net @tzk105.nic.ua
...
;; ANSWER SECTION:
default._domainkey.lappyfamily.net. 14400 IN TXT "v=DKIM1\; k=rsa\; p=MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhAOOL77/ce8tGGPpMOOEV/3RQyDza+O9onYOboDZ2SQPbOvWZvA0k8GCnZm/5ZsvR8VOFrimJ/jYYQLJfi+cCJDlqd1Yl7rMP1Xo9t+W55rvjKt9UYo6Ean05h1K6qd6B3QIDAQAB\;"

Про те, який використовується селектор (default), я дізнався з надісланого листа -

...
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lappyfamily.net; s=default;
...

cPanel може не подобатися те, що сервер не є головним DNS для цієї зони, але це повідомлення можна спокійно проігнорувати:

/galleries/dropbox/dkim-warning-lf.png

Після того, як я додав дані DKIM до свого DNS, cPanel скаржитися припинила.

На даний момент окрему IP адресу можна замовити тільки через службу підтримки і коштує вона 25₴ на весь період дії хостингу. При цьому окрема IPv6 адреса не надається через відсутність підтримки у cPanel. В майбутньому остання має почати коректно працювати з новими адресами.

nic.ua працює над тим, щоб додати можливість замовлення цієї послуги через “персональний кабінет”, але мене попередили, що після цього вартість може змінитися.

Через обмеження cPanel для одного облікового запису можливо призначити тільки одну IP адресу і SSL сертифікат можна встановити тільки для одного домену. cPanel не підтримує SNI, тому використовувати SSL для більш ніж одного домену (або субдомену) не є можливим.

Це також має змінитися в майбутньому – [Case 46856] SNI ( Server Name Indicator ), SSL support in cPanel.

Особливості mod_security

На серверах встановлено модуль mod_security. Для того, щоб до сайтів не зверталися погано написані боти, mod_security фільтрує запити за заголовком User-Agent. Стандартні User-Agent для curl та lwp-request на будь-який запит будуть отримувати у відповідь 404 Not found, тому, якщо програмне забезпечення має працювати з сервісом на цьому хостингу, потрібно використовувати власні унікальні заголовки User-Agent.

Завантаження файлів

Стандартно надається доступ через FTP, підтримується SSL, але сертифікат самопідписаний. Для того, щоб змусити lftp прийняти цей SSL сертифікат, треба встановити set ssl:verify-certificate false.

Також cPanel має свій власний WebDAV сервер, але він не дозволяє змінювати режим доступу до файлів (chmod).

Результат

Мій проект успішно переїхав до nic.ua, і тепер можна спокійно вимикати домашній сервер.

В той час, коли прогресивне людство використовує VPS та створює віртуальні машини на Amazon, такий тип хостингу продовжує існувати. Для більшості простих проектів він підходить, не потрібно займатися апаратною частиною власноруч, перейматися базою даних та тим, що на дешевій VPS можна вийти за межі доступної оперативної пам’яті.

Однак на хостингу такого типу можна розміщувати тільки проекти, що не використовують програми для фонової обробки даних (наприклад, celery).

Також хостинг не підійде для проектів, що використовують більше одного домену з SSL.

Дякую співробітнику служби технічної підтримки nic.ua Дмитру Хветкевичу за допомогу в налаштуванні та вирішенні питань.