Obsah

Reverzní HTTP proxy server

K čemu je to dobré? Potřebu jsem začal mít ve chvíli, kdy jsem začal více pracovat s dockerem. Najednou jsem měl několik služeb, které běží přes http a na různých portech. Přistupovat k takovým službám přes porty je nepohodlné, pro běžné uživatele prakticky nepoužitelné a ještě navíc nezabezpečené. Protože služby běží defaultně skrze HTTP.

I když je v názvu HTTP proxy server, tak je jednoduché ho změnit na HTTPS server.

Reverzní proxy lze rozjet minimálně na 2 serverech. Apache nebo nginx. Server bude naslouchat na klasických portech 80 a 443 a přesměruje komunikaci na localhost:9000 (Portainer) nebo na localhost:1880 (Node RED). Uživatel porty neuvidí, bude přistupovat k serveru klasicky.

Apache

Nejprve jsem potřeboval zapnout potřebné moduly:

sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests rewrite headers
sudo systemctl restart apache2

U Apache se upraví konfigurační soubor /etc/apache2/sites-available/000-default.conf.

<VirtualHost *:80>
    ProxyPreserveHost On

    ProxyPass / http://127.0.0.1:1880/
    ProxyPassReverse / http://127.0.0.1:1880/
</VirtualHost>

Tady pozor na lomítka na konci za portem. Bez nich jsem měl problémy. Návod jsem čerpat odsud: How To Use Apache as a Reverse-Proxy with mod_proxy on Ubuntu 20.04. Další návod je zde: https://www.howtogeek.com/devops/how-to-set-up-a-reverse-proxy-with-apache/.

Po úpravě konfiguračního souboru je potřeba reloadnout konfiguraci nebo restartovat apache.

sudo systemctl reload apache2

zapnutí HTTPS

Pro zapnutí https je potřeba zapnout další modul:

sudo a2enmod ssl
sudo systemctl restart apache2

Konfigurační soubor /etc/apache2/sites-enabled/default-ssl.conf pak může vypadat takto:

 <VirtualHost *:443>
 
        SSLEngine On
 
        # Set the path to SSL certificate
        # Usage: SSLCertificateFile /path/to/cert.pem
        SSLCertificateFile /etc/apache2/ssl/file.pem
 
 
        # Servers to proxy the connection, or;
        # List of application servers:
        # Usage:
        # ProxyPass / http://[IP Addr.]:[port]/
        # ProxyPassReverse / http://[IP Addr.]:[port]/
        # Example: 
        ProxyPass / http://127.0.0.1:1880/
        ProxyPassReverse / http://127.0.0.1:1880/
 
        # Or, balance the load:
        # ProxyPass / balancer://balancer_cluster_name
 
    </VirtualHost>

problém - Lost Connection..

Problém byl, že u Node REDu apache nefungoval jak má. Po chvíli Node RED vypisoval hlášení: „Lost connection..“. Hledal jsem v diskusích a nenašel jsem uspokojivé řešení, které by fungovalo. Nakonec jsem na podnět v diskusích přešel na nginx - ten byl skutečně řešením.

Při testování umělé inteligence chatGPT jsem vznesl dotaz a našla mi řešení pro apache, které se zdá být funkční. Problém je opravdu s web sockety a přidal jsem do konfiguračního souboru toto:

RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*)           ws://localhost:1880/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*)           http://localhost:1880/$1 [P,L]

reverzní proxy pro více služeb

S touto konfigurací jsem se natrápil nejvíce. Chtěl jsem, aby jednotlivé služby běžely na těchto url:

Pozor - je důležité na konci dát vždycky lomítko - jak v URL, tak konfiguraci, jinak jsem se setkal s problémy a dlouho trvalo, než jsem na toto přišel. Konfigurační soubor apache pak bude obsahovat tyto řádky (počítám s websockety pro nodered):

RewriteEngine on

RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/nodered/(.*) ws://localhost:1880/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule ^/nodered/(.*) http://localhost:1880/$1 [P,L]

ProxyPass /nodered/ http://localhost:1880/
ProxyPassReverse /nodered/ http://localhost:1880/

ProxyPass /portainer/ http://localhost:9000/
ProxyPassReverse /portainer/ http://localhost:9000/

úpravy pro Nextcloudpi

Nejprve jsem do konfiguračního souboru Apache zadal tyto řádky:

RewriteRule ^/nextcloud/(.*) ws://localhost:8880/$1 [P,L]  
RewriteRule ^/nextcloud/(.*) http://localhost:8880/$1 [P,L]

Poté je podle návodu k nextcloudu nutné editovat soubor config.php a nastavit v něm reverzní proxy. V mém případě jsem musel zadat něco takového:

'trusted_proxies' =>
array (
  11 => '127.0.0.1',
  12 => '::1',
  13 => 'e906aaab10d6',
  14 => '172.27.0.3',
  15 => '192.168.1.20'
),
'overwriteprotocol' => 'https',
'overwritehost' => 'mojedomena.cz',
'overwritewebroot'  => '/nextcloud',
'overwritecondaddr' => '^192\.168\.1\.20$'

Bohužel jsem zjistil, že konfigurace nebyla dostačující. Webové rozhraní fungovalo, ale když jsem se snažil použít klienta na automatickou synchronizaci, tak klient měl problém s https protokolem. Prozatím jsem hledání řešení vzdal, protože jsem ani po několika hodinách nebyl úspěšný.

PiHole

Pro konfiguraci Pi Hole bylo nutné do Apache zadat tyto řádky:

ProxyPass /pihole/ http://localhost:8089/admin/       
ProxyPassReverse /pihole/ http://localhost:8089/admin/

Stejně služba nefungovala jak má, protože se mi nevypisovala uložená data. Pak jsem narazil na tuto diskusi s řešením: https://www.reddit.com/r/Actualfixes/comments/ulzrbj/fix_pihole_behind_proxy_error_invalid_json/

Řešení popisuje, že je potřeba přizpůsobit nastavení lighttpd v docker kontejneru. V docker konterjneru přidat do souboru /etc/lightttpd/external.conf tento řádek (nastavit tam IP adresu serveru):

setenv.add-environment = ( "VIRTUAL_HOST" => "<your-domain>" )

Řešení bude funkční pouze do chvíle aktualizaci kontejneru. Proto jsem do docker compose souboru přidal tento řádek:

volumes:
  - /mojecesta/external.conf:/etc/lighttpd/external.conf

Nejprve ale bylo potřeba na disku vytvořit soubor /mojecesta/external.conf jinak se mi nepodařilo kontejner spustit.

Pak jsem ale našel lepší řešení v dokumentaci docker Pi Hole kontejneru. Výsledná konfigurace pro docker-compose pak vypadá takto:

pihole:
  container_name: pihole
  image: pihole/pihole:latest
  ports:
  - "8089:80/tcp"
  - "53:53/tcp"
  - "53:53/udp"
  - "67:67/udp"
  environment:
  - TZ=Etc/UTC
  - WEBPASSWORD=supertajneheslo
  - INTERFACE=eth0
  - VIRTUAL_HOST=192.168.1.20
  volumes:
  - ./volumes/pihole/etc-pihole:/etc/pihole
  - ./volumes/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
    #- ./volumes/pihole/external.conf:/etc/lighttpd/external.conf
  dns:
  - 127.0.0.1
  - 1.1.1.1
  cap_add:
  - NET_ADMIN
  restart: unless-stopped

V závěru jsem objevil ještě jeden problém. Pi Hole po přihlášení přesměrovává na IP_ADRESA_SERVER/admin . Takže po přihlášení do Pi Hole jsem přesměrován mimo reverzní proxy. Nakonec jsem to vyřešil tak, že jsem Pi Hole spustil na IP_ADRESA_SERVER/admin namísto /pihole. Funkční konfigurace Apache pak vypadá takto:

RewriteRule ^(.*)/pihole/$ $1/admin/ [R]
ProxyPass /admin/ http://localhost:8089/admin/
ProxyPassReverse /admin/ http://localhost:8089/admin/

Setkal jsem se s problémem, když jsem pihole nemohl nastartovat, protože port 53 byl obsazený již nějakou jinou službou. V mém případě to byl connect manager. Pomohla editace souboru /etc/connman.prefs (v distribuci OSMC je soubor tady /etc/osmc/prefs.d/connman) a nastavit:

dnsproxy=no

A pak restartovat connection managera:

systemctl restart connman

Další tipy k samotnému Pi Hole:

A tady odkaz na servery s blocklisty:

Nginx

Přechod na nginx trochu zabolel. Ze začátku jsem dělal chybu, že za každým konfiguračním příkazem musí být středník. Rovnou ukazuji konfiguraci serveru, kdy přesměrovávám http na https a provozuji 2 služby. Node RED a portainer. Při konfiguraci mi pomohl zdroj Behind a reverse proxy.

Nejprve defaultní server s Node RED v souboru: /etc/nginx/sites-enabled/default:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        listen 443 ssl default_server;
        #listen [::]:443 ssl default_server;

        ssl_certificate         /etc/ssl/server-cert.pem;
        ssl_certificate_key     /etc/ssl/server-key.pem;

        server_name garmin.cn;

        location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        #try_files $uri $uri/ =404;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;

        proxy_pass http://localhost:1880;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }
}

Pak editaci služby portainer v souboru: /etc/nginx/sites-enabled/portainer.garmin.cn. Tady už řeším automatické přesměrování z HTTP na HTTPS.

server {
        listen 80;
        server_name portainer.garmin.cn;
        return 301 https://portainer.garmin.cn$request_uri;
}


server {


        listen 443 ssl;

        server_name portainer.garmin.cn;




        ssl_certificate /etc/ssl/server-cert.pem;
        ssl_certificate_key /etc/ssl/server-key.pem;

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        #root /var/www/html;

        # Add index.php to the list if you are using PHP
        #index index.html index.htm index.nginx-debian.html;


        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;

                proxy_pass http://localhost:9000;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }

}