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 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):
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/ ProxyRequests off ProxyPass /portainer/ http://localhost:9000/ ProxyPassReverse /portainer/ http://localhost:9000/
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.