awolf's blog

Undefined symbol SSLv2_method while running bundle install

08 October 2012

If you get an error message undefined symbol: SSLv2_method after running bundle install inside Rails project’s dir and if you use RVM on Ubuntu, here is a solution to this problem. Note that it’s better to take care of this problem before installing Ruby. Otherwise, you have to reinstall Ruby later.

Everything in the Ruby world changes quite quickly, so it’s better to know the exact versions of software I used while testing this solution.

  • Ruby 1.9.3-p194
  • RVM 1.15.8 (stable)

Activate RVM if you haven’t already done that.

$ source ~/.rvm/scripts/rvm

Install openssl library that has SSLv2 support.

$ rvm pkg install openssl

Install Ruby specifying the path to the openssl library. If you have already installed Ruby, replace "install" with "reinstall".

$ rvm install 1.9.3 --with-openssl-dir=$rvm_path/usr

And that’s it. Now you can install gems.

$ bundle install

Игнорирование изменений файла в локальном git-репозитории

03 October 2012

Последнее время часто сталкиваюсь с ситуацией, когда файл должен присутствовать в удаленном git-репозитории, но не нужно отслеживать его изменения в локальном репозитории. Самый частый пример — это конфиги. Я забиваю конфиг строками типа #put your database password here, отправляю эту версию на гитхаб, дальше подставляю уже реальные значения, и вот их-то уже вовсе не обязательно хранить на гитхабе.

Решение просто и изящно.

$ git update-index --assume-unchanged FILENAME

После этой команды изменения файла FILENAME отслеживаться не будут. Правда, у такого подхода есть и негативная сторона — если в удаленном репозитории окажется новая версия файла, то при пулле локальная версия будет переписана, об этом надо помнить.

Если нужно отменить «заморозку» файла, есть обратная команда.

$ git update-index --no-assume-unchanged FILENAME
git

Настройка OpenVPN для выхода в интернет

21 September 2012

Полезно иметь под рукой VPN, настроенный для выхода через него в интернет. Мне, например, он нужен для того, чтобы спокойно лазить в инет через открытые WiFi-точки, не боясь за свои пароли (в 2012 году все еще есть сайты, которые не используют HTTPS).

Настройка сервера (Ubuntu)

Устанавливаем OpenVPN из репозитория.

$ sudo apt-get install openvpn

Генерируем сертификаты и ключи (которые надо держать в секрете). Нам понадобятся:

  • Сертификаты для сервера и для каждого клиента, а также приватные ключи для них.
  • CA-сертификат ca.crt и ключ ca.key для подписи сертификатов сервера и клиентов.
  • Ключ Diffie Hellman. Нужен для установления защищенного соединения.

В составе OpenVPN есть утилита для генерации ключей, которая лежит в /usr/share/doc/openvpn/examples/easy-rsa/2.0/. В файле vars можно поменять настройки под себя, можно оставить дефолтные.

Инициализация (обращаем внимание на то, что после первой точки есть пробел):

$ . ./vars
$ ./clean-all

Генерируем ca.crt и ca.key, сертификаты и ключи для сервера/клиентов и ключ Diffie Hellman. На вопросы можно не отвечать и просто давить Enter.

$ ./build-ca 
$ ./build-key-server server_name
$ ./build-key client_name1
$ ./build-key client_name2
$ ./build-dh

Копируем нужные на сервере файлы в /etc/openvpn/.

$ cp ./keys/ca.crt /etc/openvpn/
$ cp ./keys/server_name.crt /etc/openvpn/
$ cp ./keys/server_name.key /etc/openvpn/
$ cp ./keys/dh1024.pem /etc/openvpn/

Ключ ca.key используется только для подписи сертификатов — поэтому его можно не держать в /etc/openvpn/, но обязательно нужно сохранить в надежном месте и никому не показывать.

Разбираемся с конфигом. В /usr/share/doc/openvpn/examples/sample-config-files/ есть шаблон server.conf, в нем подробно прокомментированы все опции. Мой конфиг выглядит примерно так:

port 1194                       # дефолтный порт
proto upd                       # используемый протокол
dev tun                         # "dev tun" --- для IP-туннеля
ca ca.crt                       # CA-сертификат
cert server_name.crt            # сертификат сервера
key server_name.key             # приватный ключ сервера
dh dh1024.pem                   # ключ Diffie Hellman
server 10.8.0.0 255.255.255.0   # используемая подсеть
ifconfig-pool-persist ipp.txt   # файл с адресами клиентов
push "redirect-gateway"         # перенаправлять весь трафик через VPN
keepalive 10 120                # пинговать каждые 10 сек, 
                                # если нет ответа 120 сек --- отваливаться
comp-lzo                        # использовать сжатие
user nobody                     # на всякий случай даем как можно меньше прав
group nogroup
persist-key                     # не перечитывать ключи
persist-tun                     # не переоткрывать tun-device
log-append /var/log/openvpn.log # лог-файл
verb 4                          # уровень детализации лога

Прописываем правила iptables. Нужно разрешить клиентам из подсети 10.8.0.0/24 доступ в интернет, разрешить принимать пакеты из интернета и пропустить трафик клиентов через NAT.

iptables -A FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Чтобы правила не сбросились после перезагрузки, добавляем их в /etc/rc.local.

Включаем форвардинг в ядре: в /etc/sysctl.conf добавляем (или раскомментируем) строку

net.ipv4.ip_forward=1

Чтобы форвардинг заработал без перезагрузки, делаем

$ echo 1 > /proc/sys/net/ipv4/conf/all/forwarding

Если клиент уже находится за NAT-ом, проброс трафика не заработает, а в логах можно будет найти строки вроде "MULTI: bad source address from client [a.b.c.d], packet dropped" — так как у OpenVPN нет правил для обработки пакетов из подсети a.b.c.0/24, они дропаются. Поэтому прописываем нужные правила: в /etc/openvpn/server.conf добавляем строки

client-config-dir ccd           # директория с настройками для клиентов
route a.b.c.0 255.255.255.0     # обрабатывать пакеты из подсети a.b.c.0/24

а в /etc/openvpn/ccd/ создаем файл client_name1.conf и в нем пишем

iroute a.b.c.0 255.255.255.0    # разрешаем доступ к VPN из подсети a.b.c.0/24

Настройка серверной части закончена, перезапускаем OpenVPN.

$ sudo service openvpn restart

Настройка клиента (Ubuntu)

Во-первых, надо установить OpenVPN на клиенте.

$ sudo apt-get install openvpn

Во-вторых, с сервера надо скопировать CA-сертификат ca.crt, сертификат client_name1.crt и ключ client_name1.key.

Есть два способа настройки клиентской части OpenVPN. Первый — с использованием конфига в /etc/openvpn/. В /usr/share/doc/openvpn/examples/sample-config-files/ есть шаблон client.conf с комментариями. Мой конфиг выглядит примерно так:

client                          # указываем, что это клиент
dev tun                         # на сервере и клиенте должно совпадать
proto udp                       # на сервере и клиенте должно совпадать
remote a.b.c.d 1194             # адрес и порт сервера
resolv-retry infinite           # пытаться достучаться до сервера бесконечно
nobind                          # не использовать какой-то особый порт
user nobody                     # на всякий случай даем как можно меньше прав
group nogroup                   # на всякий случай даем как можно меньше прав
persist-key                     # не перечитывать ключи
persist-tun                     # не переоткрывать tun-device
mute-replay-warnings            # подавлять предупреждения о повторных пакетах
ca ca.crt                       # CA-сертификат
cert client_name1.crt           # сертификат клиента
key client_name1.key            # приватный ключ клиента
comp-lzo                        # на сервере и клиенте должно совпадать
log-append /var/log/openvpn.log # лог-файл
verb 4                          # уровень детализации лога

Второй способ — настройка через GUI. Ставим плагин для network manager:

$ sudo apt-get install network-manager-openvpn

И добавляем VPN в Network Connections (VPN Connections → Configure VPN → Add). Там все просто и понятно: нужно вбить адрес сервера и указать путь к ca.crt и клиентскому сертификату/ключу. Остальные настройки (протокол, порт, использовать ли сжатие, etc) тоже можно поменять.

Замечание насчет DNS: домены могут не резолвиться при перенаправлении трафика через VPN, если используются DNS-сервера провайдера, доступные только из его локальной сети. Поэтому лучше использовать какие-нибудь публичные DNS-сервера, например, Google Public DNS (8.8.8.8 и 8.8.4.4).

Меняем местами ветки в git

18 August 2012

Недавно понадобилось поменять местами master-ветку git с другой, devel, в которой я вел разработку последнее время. При этом ветка devel не была основана на master, поэтому я хотел обойтись без слияния и старую master превратить в legacy, а devel превратить в master.

Собственно, решение.

Переименовываем ветки в локальном репозитории.

$ git branch -m master legacy
$ git branch -m devel master

В админке репозитория (на Github, Bitbucket, etc) устанавливаем devel веткой по умолчанию (иначе сервер не даст выполнить следующий шаг)

Удаляем ветку master на сервере.

$ git push origin :master

Пушим новую ветку master (которая на самом деле старая devel) на сервер.

$ git push origin master:master

Пушим новую ветку legacy (которая на самом деле старая master) на сервер.

$ git push origin legacy:legacy

В админке устанавливаем master веткой по умолчанию.

Удаляем ветку devel на сервере

$ git push origin :devel

Если с репозиторием работает кто-то еще, лучше либо вообще так не делать, либо предупредить. Иначе при попытке сделать pull или push в других локальных репозиториях будет ололо.

git

Деплоймент Flask + uWSGI + nginx

16 August 2012

Flask — это веб-фреймворк на Python, который отлично подходит для написания небольших проектов. Для запуска приложений на нем я использую связку uWSGI с nginx. На офсайте Flask есть руководство, посвященное uWSGI, но оно хреновое — зачем руками стартовать приложение, когда можно написать для него конфиг, который будет подхватываться при рестарте.

Руководство проверено для Flask 0.8, uWSGI 1.0.3, nginx 1.1.19.

Создаем virtualenv и ставим Flask.

$ virtualenv env
$ source env/bin/activate
$ pip install flask

Ставим uWSGI, nginx и плагин для Python для uWSGI. Под Debian я ставлю все из testing-репозитория.

$ sudo apt-get install uwsgi nginx uwsgi-plugin-python

nginx

Подробную настройку nginx оставим гуру этого дела, я ограничусь лишь основным. В /etc/nginx/sites-available/ создаем новый конфиг, flask.conf, например, в нем пишем:

upstream flask_serv {
    server unix:/tmp/flask.sock;
}

server {
    listen 80;
    server_name <имя_сайта>;

    location / {
        uwsgi_pass flask_serv;
        include uwsgi_params;
    }

    location /static/ {
        root /путь/к/статике/;
    }
}

В /etc/nginx/sites-enabled/ надо кинуть символическую ссылку на этот конфиг

$ sudo ln -s /etc/nginx/sites-available/flask.conf 
/etc/nginx/sites-enabled/flask.conf

uWSGI

Теперь в /etc/uwsgi/apps-available/ создаем конфиг для uWSGI flask.xml следующего содержания:

<uwsgi>
    <socket>/tmp/flask.sock</socket>
    <pythonpath>/путь/к/директории/с/приложением/</pythonpath>
    <module>app:app</module>
    <plugins>python27</plugins>
    <virtualenv>/путь/к/virtualenv/</virtualenv>
</uwsgi>

В /etc/uwsgi/apps-enabled/ тоже надо создать символическую ссылку на конфиг

$ sudo ln -s /etc/uwsgi/apps-available/flask.xml 
/etc/uwsgi/apps-enabled/flask.xml

Само приложение, соответственно, должно называться app.py и в минимальном виде может выглядеть примерно так:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "It works!"

if __name__ == "__main__":
    app.run()

На этом все, рестартуем nginx и uWSGI и радуемся жизни.

←previous / next→