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