Работа с nginx + lua

nginx redis lua - record post params

Generally with payment gateways, we receive an http request to confirm a transaction. This transaction is important and the http requests must be processed. For example, we want our stack to stay available during a deployment.
Our goal is to record the payload received from a payment pingback in a Redis queue, without involving the application code.
nginx allows lua scripting with thirdparty modules lua-nginx-module.
For Redis we will use the lua-resty-redis module.
If you are on a Debian system and don't want to recompile nginx you can use the nginx-extras and lua-nginx-redispackages.
aptitude install redis nginx-extras lua-nginx-redis lua-json
Then we can create a server with this nginx config:
# on Debian the lua-nginx-redis is installed here
lua_package_path "/usr/share/lua/5.1/nginx/?.lua;;";
server {
  server_name payment.local;
  location / {
     content_by_lua '
-- connect to redis
local redis = require "redis"
local json = require "json"
local red = redis:new()
red:set_timeout(1000) -- 1 sec
local ok, err = red:connect("", 6379)
if not ok then
    ngx.say("failed to connect: ", err)

-- read post data
local args = ngx.req.get_post_args()
if not args then
    ngx.say("failed to get post args: ", err)

local args_to_redis = json.encode(args)

-- record it to redis
local ans, err = red:lpush("payment", args_to_redis)
if not ans then
    ngx.say("failed to run rpush: ", err)
Once nginx is reloaded, it can be tested with this curl command:
curl -v -XPOST \
    -d "TPE=1234567&date=05%2f12%2f2006%5fa%5f11%3a55%3a23&montant=62%2e75EUR&reference=ABERTYP00145&MAC=e4359a2c18d86cf2e4b0e646016c202e89947b04&texte-libre=LeTexteLibre&code-retour=payetest&cvx=oui&vld=1208&brand=VI&status3ds=1&numauto=010101&originecb=FRA&bincb=010101&hpancb=74E94B03C22D786E0F2C2CADBFC1C00B004B7C45&ipclient=127%2e0%2e0%2e1&originetr=FRA&veres=Y&pares=Y" \
We can get the params, for example, on a Ruby script that parses the recorded post from nginx.
require 'redis'
require 'json'
redis = Redis.new
list, element = redis.blpop("payment")


Дополнительные ссылки на материалы:

Какой то конфиг OpenVPN

# Sample OpenVPN configuration file for
# home using SSL/TLS mode and RSA certificates/keys.
# '#' or ';' may be used to delimit comments.
# Use a dynamic tun device.
# For Linux 2.2 or non-Linux OSes,
# you may want to use an explicit
# unit number such as "tun1".
# OpenVPN also supports virtual
# ethernet "tap" devices.
dev tun
proto udp
# is our local VPN endpoint (home).
# is our remote VPN endpoint (office).
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS           BROADCAST MULTICAST  MTU:1500  Metric:1"
push "dhcp-option DNS"
push "reneg-sec 0"
push "rcvbuf 262144"
push "sndbuf 262144"
# Our up script will establish routes
# once the VPN is alive.
; up ./internal.routes
script-security 2 execve
client-connect /usr/local/bin/openvpn.updown.sh
client-disconnect /usr/local/bin/openvpn.updown.sh

# Diffie-Hellman Parameters (tls-server only)
dh /etc/openvpn/external-keys/dh1024.pem
# Certificate Authority file
ca /etc/openvpn/external-keys/ca.crt
# Our certificate/public key
cert /etc/openvpn/external-keys/openvpn.vpnunlimitedapp.com.crt
# Our private key
key /etc/openvpn/external-keys/openvpn.vpnunlimitedapp.com.key
# OpenVPN 2.0 uses UDP port 1194 by default
# (official port assignment by iana.org 11/04).
# OpenVPN 1.x uses UDP port 5000 by default.
# Each OpenVPN tunnel must use
# a different port number.
# lport or rport can be used
# to denote different ports
# for local and remote.
port 443
# Downgrade UID and GID to
# "nobody" after initialization
# for extra security.
; user nobody
; group nogroup

# If you built OpenVPN with
# LZO compression, uncomment
# out the following line.
# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
ping 5
ping-restart 60
push "ping 5"
push "ping-exit 30"
#keepalive 10 120
# For extra security beyond that provided
# by SSL/TLS, create an "HMAC firewall"
# to help block DoS attacks and UDP port flooding.
# Generate with:
#   openvpn --genkey --secret ta.key
# The server and each client must have
# a copy of this key.
# The second parameter should be '0'
# on the server and '1' on the clients.
;tls-auth /etc/openvpn/external-keys/ta.key 0 # This file is secret
# The persist options will try to avoid
# accessing certain resources on restart
# that may no longer be accessible because
# of the privilege downgrade.
# Output a short status file showing
# current connections, truncated
# and rewritten every minute.
status openvpn-status-udp-443.log 10
# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
# the "\Program Files\OpenVPN\log" directory).
# Use log or log-append to override this default.
# "log" will truncate the log file on OpenVPN startup,
# while "log-append" will append to it.  Use one
# or the other (but not both).
log-append  /var/log/openvpn-external-udp-443.log
# Send a UDP ping to remote once
# every 15 seconds to keep
# stateful firewall connection
# alive.  Uncomment this
# out if you are using a stateful
# firewall.
; ping 15
# Uncomment this section for a more reliable detection when a system
# loses its connection.  For example, dial-ups or laptops that
# travel to other locations.
; ping 15
; ping-restart 45
; ping-timer-rem
; persist-tun
; persist-key
# Verbosity level.
# 0 -- quiet except for fatal errors.
# 1 -- mostly quiet, but display non-fatal network errors.
# 3 -- medium output, good for normal operation.
# 9 -- verbose, good for troubleshooting
verb 3
# Silence repeating messages.  At most 20
# sequential messages of the same message
# category will be output to the log.
mute 20
management /var/run/openvpn-udp-443.sock unix
#management 9868
reneg-sec 0
rcvbuf 262144
sndbuf 262144

Фотосессия на корпоративный портал

Когда-то и я был молодой


Читаем книги на работе.

Proxy Auto Configuration (PAC)

Proxy Auto Configuration (PAC)

В рунете мало информации об такой замечательной вещи как «Автоматическая настройка прокси сервера». В этой статье я постараюсь подробно остановиться на данном вопросе.

Суть технологии заключается в том, что браузер читает специальный файл написаный на языке Javascript, в котором определена только одна функция:

function FindProxyForURL(url, host)

url – полный URL запрашиваемого документа
host – имя поста извлекаемое из URL. Этот параметр необходим только для удобства. Он содержит всё от :// и до первого / или :. Номер порта не включается в этот параметр.

Функция возвращает строку содержащую один или несколько способов доступа к запрашиваемому документу. Формат строки следующий:

null — если строка null, то использовать прокси сервер не нужно;
DIRECT — прямое соединение без использования прокси;
PROXY host:port — определяет какой прокси сервер необходимо использовать;
SOCKS host:port — определяет SOCKS сервер который необходимо использовать.

Строка может содержать несколько приведенных выше параметров разделенных точкой с запятой. Тогда браузер будет перебирать их по очереди пока не найдёт доступный прокси сервер.
В главной функции могут быть вызваны следующие функции:
  • isPlainHostName(host) возвращает true если строка host не содержит точек ("."). 
  • dnsDomainIs(hostdomain) вернет true если domain принадлежит host
  • localHostOrDomainIs(hosthostdomain) возвращает true если строка host (имя хоста или домена) содержится в строке hostdomain
  • isResolvable(host) возвращает true если возможно определить IP адрес для заданной строки host
  • isInNet(hostpatternmask) возвращает true если IP адрес или имя хоста в строке host соответствует шаблону pattern и маске mask
  • dnsResolve(host) возвращает IP адрес для заданного host
  • myIpAddress() возвращает IP адрес компьютера
  • dnsDomainLevels(host) возвращает количество точек в строке host. Другими словами уровень домена
  • shExpMatch(strshellexp) вернет true если строка str соответствует регулярному выражению в строке shellexp (формат регулярных выражений shellexp, а не regexp). Например shExpMatch("a/b/c","*/b/*") вернет true
  • weekdayRange(wd1 [, wd2 ][, "GMT"]) вернет true если текущая дата или дата заданная в параметре GTM, соответствует заданному дню недели или диапазону дней. Дни недели записываются в закавыченной строке из следующих вариантов (SUN|MON|TUE|WED|THU|FRI|SAT)
  • dateRange([day1] [,month1] [,year1] [,day2] [,month2] [,year2] [,"GMT"]) вернет true если текущая дата или дата заданная в параметре GTM попадает в указанный диапазон. Название месяца задается закавыченной строкой из следующих вариантов (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
  • timeRange(hour1minute1second1hour2minute2second2 [, "GMT"])
  • timeRange(hour1minute1hour2minute2 [, "GMT"])
  • timeRange(hour1hour2 [, "GMT"])
  • timeRange(hour [, "GMT"])

Браузеры Firefox и Internet Explorer поддерживает только системную кодировку в PAC файле и не поддерживают Unicode кодировки, такие как UTF-8.

Приведу небольшой пример:

function FindProxyForURL(url, host)
 if (isPlainHostName(host) || dnsDomainIs(host, ".mydomain.com"))
  return "DIRECT";
 else if (shExpMatch(host, "*.com"))
  return "PROXY proxy1.mydomain.com:8080; " +
   "PROXY proxy4.mydomain.com:8080";
 else if (shExpMatch(host, "*.edu"))
  return "PROXY proxy2.mydomain.com:8080; " +
   "PROXY proxy4.mydomain.com:8080";
  return "PROXY proxy3.mydomain.com:8080; " +
   "PROXY proxy4.mydomain.com:8080";

Данный скрип говорить устанавливать браузеру прямое соединение для локальных хостов или под доменов домена .mydomain.com. Для доменов из зоны .com используются прокси серверы 1 и 4, для доменов из зоны .edu прокси 2 и 4 ну и для всех оставшихся вариантов прокси 3 и 4.

Теперь остановлюсь на вопросе как указать браузеру использовать автоматическую конфигурацию прокси серверов. Для этого есть несколько вариантов:
  • Задать адрес скрипта вручную. Скрипт выкладывается на сервер доступный для пользователя. Обычно имя скрипта proxy.dat, однако если следовать спецификации WPAD скрипт следует назвать wpad.dat. Так же сервер должен отдавать файл с MIME типом application/x-ns-proxy-autoconfig
  • Второй способ WPAD метод основанный на DNS. Подробнее можно прочесть по ссылке ru.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol
  • И третий способ WPAD, основанный на DHCP. WPAD просто выдает PAC скрипт с выбранный номером 252 в «аренду» запросившему IP. Браузер получает URL скрипта и просто качает его по ссылке. Для этого необходимо:
    1. Добавим в /etc/dhcp/dhcpd.conf следующие строчки.
      option local-pac-server code 252 = text;
      option local-pac-server "wpad.example.com:80/wpad.dat\000";
    2. Перезапустите DHCP сервер.
    Небольшой нюанс — у DHCP приоритет выше, чем у DNS, как следствие — гораздо быстрее. И можно вместо имени сайта указать его IP, в этом случае отсутствуют расходы времени на преобразование адреса в имя, что добавляет скорости. 

Настройка браузеров. В параметрах программы нужно указать определение прокси-сервера:
  1. В браузере Explorer
    Сервис -> Свойства обозревателя -> Подключения -> Настройка сети
    поставить галочку напротив опции «Автоматическое определение параметров»
    или поставить галочку напротив опции «Использовать сценарий автоматической настройки» и в поле «Адрес» написать путь до PAC файла. Например: wpad.example.com:80/wpad.dat
  2. В браузере Opera 
    Настройки -> Дополнительно -> Сеть -> Прокси-серверы
    поставить галочку напротив опции «Автоматическая конфигурация прокси-сервера» и в поле «Адрес» написать путь до PAC файла.
  3. В браузере Firefox
    выберать опции «Автоматически определять настройки прокси для этой сети»
    или выберать опцию «URL автоматической настройки сервиса прокси» и в поле «Адрес» написать путь до PAC файла.

Ещё несколько полезной информации можно почерпнуть по адресу en.wikipedia.org/wiki/Proxy_auto-config