infrastruktura domowa · reverse proxy

Routing ruchu przez Apache do usług za Tailscale

Kompletna ściąga do Twojego układu: VPS OVH → Tailscale → serwer domowy → Apache → aplikacja. Certyfikat leży na Apache, więc żadna aplikacja nie musi sama umieć HTTPS.

INTERNET mikolajfiuk.pl VPS OVH 57.128.255.40 TAILSCALE DNAT tunel SERWER DOMOWY 100.96.49.10 APACHE SSL → app
Zasada: publiczny port → DNAT na VPS → Tailscale → port HTTPS Apache → HTTP aplikacji
UsługaPubliczny adresHTTPS na serwerze domowymAplikacja
Craftyhttps://mikolajfiuk.pl:84439444127.0.0.1:8443
Strona / panel na porcie 81https://mikolajfiuk.pl:819445127.0.0.1:81
Nextcloudhttps://mikolajfiuk.pl:80808080Nextcloud
00

Najważniejsza zasada

Dla każdej kolejnej strony robimy dokładnie to samo:

PUBLICZNY PORT↓VPS — DNAT↓Tailscale↓PORT HTTPS Apache↓HTTP aplikacji

Czyli np. dla Crafty:

mikolajfiuk.pl:8443↓VPS :8443↓100.96.49.10:9444↓Apache HTTPS :9444↓127.0.0.1:8443
ℹ
Dzięki temu certyfikat jest na Apache, a sama aplikacja nie musi umieć obsługiwać HTTPS.
01

Certyfikat Let's Encrypt

Certyfikat mamy dla: mikolajfiuk.pl

Sprawdzenie
bash
sudo certbot certificates

Certyfikat znajduje się tutaj:

path
/etc/letsencrypt/live/mikolajfiuk.pl/fullchain.pem
/etc/letsencrypt/live/mikolajfiuk.pl/privkey.pem
Sprawdzenie automatycznego odnawiania
bash
sudo systemctl status certbot.timer
Test odnowienia
bash
sudo certbot renew --dry-run
⚠
Tego nie uruchamiaj regularnie ręcznie. Certbot powinien sam odnawiać certyfikat.
02

Moduły Apache

Na serwerze domowym:

bash
sudo a2enmod ssl proxy proxy_http headers

Możemy też mieć:

bash
sudo a2enmod proxy_wstunnel

Nie zaszkodzi mieć go włączonego, szczególnie przy aplikacjach korzystających z WebSocketów.

Po zmianach:

bash
sudo apache2ctl configtest

Jeżeli jest: Syntax OK to:

bash
sudo systemctl restart apache2
03

Sprawdzanie, jakie porty są zajęte

Bardzo przydatne polecenie:

bash
sudo ss -ltnp

Albo tylko konkretne:

bash
sudo ss -ltnp | grep -E ':(81|8080|8443|9444|9445)\b'

To pokazuje, co faktycznie nasłuchuje na poszczególnych portach.

04

Crafty — HTTPS na 8443

publiczny :8443→ VPS DNAT→ 100.96.49.10:9444→ Apache HTTPS→ 127.0.0.1:8443
Konfiguracja Apache
bash
sudo nano /etc/apache2/sites-available/crafty.conf
apache · crafty.conf
<IfModule mod_ssl.c>
<VirtualHost *:9444>
    ServerName mikolajfiuk.pl

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mikolajfiuk.pl/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mikolajfiuk.pl/privkey.pem

    ProxyRequests Off
    ProxyPreserveHost On
    ProxyTimeout 3600

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "8443"

    ProxyPass        / http://127.0.0.1:8443/ upgrade=websocket retry=0 timeout=3600
    ProxyPassReverse / http://127.0.0.1:8443/

    ErrorLog ${APACHE_LOG_DIR}/crafty-error.log
    CustomLog ${APACHE_LOG_DIR}/crafty-access.log combined
</VirtualHost>
</IfModule>
Włączenie
bash
sudo a2ensite crafty.conf
Sprawdzenie
bash
sudo apache2ctl configtest
Restart
bash
sudo systemctl restart apache2
05

Crafty — przekierowanie na VPS

Na VPS:

bash
sudo iptables -t nat -I PREROUTING 1 -d 57.128.255.40/32 -p tcp --dport 8443 -j DNAT --to-destination 100.96.49.10:9444

Sprawdzenie:

bash
sudo iptables -t nat -L PREROUTING -n -v --line-numbers

Test:

powershell
curl.exe -v https://mikolajfiuk.pl:8443/login -o NUL

Docelowo: https://mikolajfiuk.pl:8443/login

06

Strona na porcie 81 — HTTPS

publiczny :81→ VPS→ 100.96.49.10:9445→ Apache HTTPS :9445→ 127.0.0.1:81
Apache
bash
sudo nano /etc/apache2/sites-available/app81.conf
apache · app81.conf
<IfModule mod_ssl.c>
<VirtualHost *:9445>
    ServerName mikolajfiuk.pl

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mikolajfiuk.pl/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mikolajfiuk.pl/privkey.pem

    ProxyRequests Off
    ProxyPreserveHost On
    ProxyTimeout 3600

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "81"

    ProxyPass        / http://127.0.0.1:81/ upgrade=websocket retry=0 timeout=3600
    ProxyPassReverse / http://127.0.0.1:81/

    ErrorLog ${APACHE_LOG_DIR}/app81-error.log
    CustomLog ${APACHE_LOG_DIR}/app81-access.log combined
</VirtualHost>
</IfModule>
Włączenie
bash
sudo a2ensite app81.conf
Sprawdzenie
bash
sudo apache2ctl configtest
Restart
bash
sudo systemctl restart apache2
VPS
bash
sudo iptables -t nat -I PREROUTING 1 -d 57.128.255.40/32 -p tcp --dport 81 -j DNAT --to-destination 100.96.49.10:9445

Sprawdzenie:

bash
sudo iptables -t nat -L PREROUTING -n -v --line-numbers

Test:

powershell
curl.exe -v https://mikolajfiuk.pl:81/ -o NUL

Adres: https://mikolajfiuk.pl:81/#/login

⚠
Ważne: tutaj musi być https://, nie http://.
07

Nextcloud — HTTPS na 8080

Tutaj sytuacja jest trochę inna, bo Apache już obsługuje Nextcloud na porcie 8080.

Edytujemy istniejącą konfigurację:

bash
sudo nano /etc/apache2/sites-available/nextcloud.conf

W VirtualHoście <VirtualHost *:8080> powinno być:

apache · nextcloud.conf
<VirtualHost *:8080>
    ServerName mikolajfiuk.pl

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mikolajfiuk.pl/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mikolajfiuk.pl/privkey.pem

    ...
</VirtualHost>
ℹ
Reszty istniejącej konfiguracji Nextcloud nie usuwamy.

Potem:

bash
sudo a2enmod ssl
bash
sudo apache2ctl configtest
bash
sudo systemctl restart apache2

Test:

bash
curl -v --resolve mikolajfiuk.pl:8080:127.0.0.1 https://mikolajfiuk.pl:8080/status.php
✓
Powinno być: HTTP/1.1 200 OK
08

Nextcloud — zaufana domena

Sprawdzenie:

bash
sudo -u www-data php /var/www/nextcloud/occ config:system:get trusted_domains

Dodanie:

bash
sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 8 --value="mikolajfiuk.pl:8080"
⚠
Numer 8 jest właściwy tylko jeśli indeks 8 jest wolny. Najpierw zawsze warto wykonać get.

Adres publiczny:

bash
sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value="https://mikolajfiuk.pl:8080"

Adres Nextcloud: https://mikolajfiuk.pl:8080/

09

VPS — zapisanie reguł

Po dodaniu wszystkich reguł:

bash
sudo netfilter-persistent save

Sprawdzenie:

bash
sudo iptables -t nat -L PREROUTING -n -v --line-numbers

I dobrze również zrobić kopię:

bash
sudo iptables-save | sudo tee /root/iptables-backup.rules >/dev/null
10

Najważniejsze testy

Sprawdzenie Apache
bash
sudo apache2ctl configtest
Restart Apache
bash
sudo systemctl restart apache2
Czy Apache działa?
bash
sudo systemctl status apache2
Jakie porty nasłuchują?
bash
sudo ss -ltnp
Certyfikat
bash
sudo certbot certificates
Test certyfikatu z Windowsa
powershell
curl.exe -v https://mikolajfiuk.pl/ -o NUL
Crafty
powershell
curl.exe -v https://mikolajfiuk.pl:8443/login -o NUL
Strona na 81
powershell
curl.exe -v https://mikolajfiuk.pl:81/ -o NUL
Nextcloud
powershell
curl.exe -v https://mikolajfiuk.pl:8080/status.php
11

Logi Apache — bardzo ważne przy problemach

Crafty
bash
sudo tail -f /var/log/apache2/crafty-error.log
Port 81
bash
sudo tail -f /var/log/apache2/app81-error.log
Nextcloud
bash
sudo tail -f /var/log/apache2/error.log

Możesz też sprawdzić wszystkie ostatnie błędy:

bash
sudo journalctl -u apache2 -n 100 --no-pager
12

Uniwersalny przepis dla kolejnej strony

Jeżeli kiedyś powiesz: „Mam aplikację na porcie 1234 i chcę ją wystawić jako https://mikolajfiuk.pl:1234” — robimy to samo, co zawsze.

Na serwerze domowym — wybieramy wolny port, np. 9450
aplikacja :1234↓Apache HTTPS :9450
apache
<VirtualHost *:9450>
    ServerName mikolajfiuk.pl

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mikolajfiuk.pl/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mikolajfiuk.pl/privkey.pem

    ProxyRequests Off
    ProxyPreserveHost On

    RequestHeader set X-Forwarded-Proto "https"

    ProxyPass        / http://127.0.0.1:1234/ upgrade=websocket retry=0
    ProxyPassReverse / http://127.0.0.1:1234/
</VirtualHost>

Potem:

bash
sudo a2ensite nazwa.conf
sudo apache2ctl configtest
sudo systemctl restart apache2
Na VPS
bash
sudo iptables -t nat -I PREROUTING 1 -d 57.128.255.40/32 -p tcp --dport 1234 -j DNAT --to-destination 100.96.49.10:9450

I:

bash
sudo netfilter-persistent save
✓
Gotowe.
⚠

Jedna bardzo ważna rzecz

⚠
Nie róbmy teraz HSTS. W tej konfiguracji jest kilka usług na różnych portach i najpierw trzeba doprowadzić wszystkie do poprawnego HTTPS. HSTS może później wymusić HTTPS tam, gdzie jakaś aplikacja działa jeszcze tylko po HTTP, i zrobić niepotrzebny bałagan.

Natomiast po zakończeniu konfiguracji wszystkich usług można zrobić jeden końcowy przegląd bezpieczeństwa: HTTP → HTTPS, HSTS, firewall, Tailscale, dostępność portów z Internetu i automatyczne odnawianie Let's Encrypt. To będzie już „ostatni szlif” całej konfiguracji.