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"; } }