====== 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 [[it:server:docker|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**. ProxyPreserveHost On ProxyPass / http://127.0.0.1:1880/ ProxyPassReverse / http://127.0.0.1:1880/ Tady pozor na lomítka na konci za portem. Bez nich jsem měl problémy. Návod jsem čerpat odsud: [[https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension-ubuntu-20-04|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/|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: 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 ==== 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 [[https://discourse.nodered.org/t/node-red-shows-lost-connection-to-server-reconnecting-beacuse-of-websocket-connection-to-wss-comms-api-failed/61220/4|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: * https://192.168.1.20/nodered/ * https://192.168.1.20/portainer 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 [[https://docs.nextcloud.com/server/20/admin_manual/configuration_server/reverse_proxy_configuration.html|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" => "" ) Ř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 [[https://github.com/pi-hole/docker-pi-hole#environment-variables|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: {{youtube>62j2UB3No3E?}} A tady odkaz na servery s blocklisty: * https://avoidthehack.com/best-pihole-blocklists * https://firebog.net/ ===== 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 [[https://socket.io/docs/v3/reverse-proxy/|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"; } }