Table of Contents

Задача

Мне понадобилось сделать reverse proxy с поддержкой SSL на роутере с OpenWrt LEDE 18.06.
Предвосхищая вопрос “зачем?” - для бекапа я пользуюсь неплохим бесплатным хостингом, который отказывается работать с некоторыми доменными зонами. В частности - .tk. В качестве практически бесплатного решения - я решил перенаправить трафик через мой домашний роутер со статическим внешним IP.

SSL штатными пакетами OpenWrt

В репозитории OpenWrt есть nginx, однако он собран без поддержки SSL. Многие мануалы, для поддержки SSL рекомендуют пересобрать пакет nginx с нужными фичами.
Я пошел другим путем и выяснил, что для решения этой задачи можно обойтись только пакетами из репозитория OpenWrt, возложив функцию шифрования трафика на haproxy.
Итак - nginx будет revese proxy, а haproxy будет шифровать SSL. Поехали. Попутно - получим сертификаты Let's Encrypt
Предварительно нужно изменить порт на котором работает штатный web-интерфейс OpenWrt. Для этого отредактируем файлик /etc/config/uhttpd.

Ставим пакеты

Ставим пакеты из консоли, либо из web-интерфейса.

opkg update
opkg install nginx haproxy luci-ssl-openssl curl ca-bundle nano

Конфигурация nginx

/etc/nginx/nginx.conf

user nobody nogroup;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    sendfile        on;
    keepalive_timeout  65;

    server {
    listen 80 default_server;
       return 444;
    }

    server {
        listen       80;
        server_name  wiki.autosys.tk;

        location /.well-known/acme-challenge/ {
            root   /www;
        }

        location / {
                proxy_pass http://redmike.unaux.com:80;
        }
        location /cgi-bin/ {
                proxy_pass http://127.0.0.1:8080;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
        }
        location /luci-static/ {
                proxy_pass http://127.0.0.1:8080;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
        }

    }
}

Перезапускаем nginx:

/etc/init.d/nginx restart

Получаем сертификат

Будем получать сертификат Let's Encrypt с помощью acme.sh

curl https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh > acme.sh
chmod a+x "acme.sh"
./acme.sh --install
cd /root/.acme.sh
DOMAIN=wiki.autosys.tk
./acme.sh --issue -d $DOMAIN -w /www

Если все прошло без ошибок, то объединяем сертификат и ключ в файл .pem

cat /root/.acme.sh/wiki.autosys.tk/wiki.autosys.tk.cer /root/.acme.sh/wiki.autosys.tk/wiki.autosys.tk.key > /root/wiki.autosys.tk.pem

Конфигурация haproxy

В конфигурации haproxy прописан сертификат, который мы получили на предыдущем этапе

/etc/haproxy.cfg

global
    maxconn 4096

defaults
    mode    http
    option forwardfor
    option http-server-close
    option  httplog
    option  dontlognull
    retries 3
    option redispatch
    maxconn 2000
    timeout connect     5000
    timeout client     50000
    timeout server     50000
    #default-server init-addr none

frontend www-https
    bind *:443 ssl crt /root/wiki.autosys.tk.pem
    reqadd X-Forwarded-Proto:\ https

    # Define hosts
    acl host_wiki hdr(host) -i wiki.autosys.tk

    ## figure out which one to use
    use_backend wiki-backend if host_wiki
    default_backend wiki-backend

backend wiki-backend
    redirect scheme https if !{ ssl_fc }
    server wiki-node1 127.0.0.1:80 check