Toto je starší verze dokumentu!
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
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.
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"; } }
limit, který jsem nevyřešil
Pokud máme doménu, tak je to všechno v pořádku. Každou službu můžeme zařadit pod subdoménu. V mém případě tedy Node RED běží pod doménou garmin.cn a portainer pod portainer.garmin.cn.
Problém ovšem nastává, když jsem v lokální síti a nevyužívám lokální dns. V tu chvíli chci volat pouze IP adresu a za ni lomítkem určit službu. Tedy například: 192.168.1.20/portainer. A to se mi právě nepodařilo vyřešit.
Jedna služba přes reverzní proxy obsadí IP adresu: 192.168.1.20 a už není možné pracovat se složkama alá 192.168.1.20/portainer, protože to už se snaží obsluhovat Node RED.