VPS Security Workflow: Joomla & Tailscale Protection

Dieser Workflow dokumentiert die Absicherung des Joomla-Administrationsbereichs hinter einem Tailscale-Netzwerk unter Verwendung von HestiaCP und NextDNS.

1. Nginx-Template (HestiaCP)

Erstelle das Template auf dem VPS unter:
/usr/local/hestia/data/templates/web/nginx/php-fpm/joomla_ts.stpl

NGINX
#=========================================================================#
# Joomla Tailscale Template - EXPLICIT IP BINDING & PROTECT               #
#=========================================================================#

server {
    # Explizite Bindung an öffentliche und Tailscale-IP für korrektes SSL
    listen      185.228.138.89:443 ssl;
    listen      100.122.105.74:443 ssl;

    server_name %domain_idn% %alias_idn%;
    root        %sdocroot%;
    index       index.php index.html index.htm;

    ssl_certificate     %ssl_pem%;
    ssl_certificate_key %ssl_key%;

    # HSTS Aktivierung (erzwingt SSL)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ [^/]\.php(/|$) {
        set $is_admin_area 0;
        set $is_allowed_user 0;

        # Prüfe auf Admin-Pfad
        if ($request_uri ~* "^/administrator/") {
            set $is_admin_area 1;
        }

        # Prüfe auf Tailscale IP-Range (100.64.0.0/10)
        if ($remote_addr ~* "100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\.") {
            set $is_allowed_user 1;
        }

        # Localhost Zugriff erlauben
        if ($remote_addr = "127.0.0.1") {
            set $is_allowed_user 1;
        }

        # Sperre: Falls Admin-Bereich aber keine Tailscale-IP
        set $block_me "${is_admin_area}${is_allowed_user}";
        if ($block_me = "10") {
            return 403;
        }

        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass %backend_lsnr%;
    }

    location /error/ { alias %home%/%user%/web/%domain%/document_errors/; }
    include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
}

2. Aktivierung

Befehle zur Zuweisung des Templates (Beispiel User blog):

Bash

TXT
sudo /usr/local/hestia/bin/v-change-web-domain-tpl blog blog.EXAMPLE.TLD joomla_ts
sudo nginx -t && sudo systemctl restart nginx

3. DNS-Konfiguration (Android & PC)

Die lokale /etc/hosts auf dem Handy ist nicht mehr nötig.

NextDNS (Rewrite)

  • Einstellung: blog.EXAMPLE.TLD -> 100.122.105.74

  • Dies zwingt das Gerät zur Nutzung der Tailscale-IP, wenn das VPN aktiv ist.

Tailscale DNS

  • Nameserver: NextDNS ID hinzufügen.

  • Global Nameservers: "Override DNS servers" aktivieren.

4. Troubleshooting

  • Fehler ERR_CERT_COMMON_NAME_INVALID: Tritt auf, wenn die listen-Anweisung im Nginx-Template nicht explizit die Tailscale-IP des VPS enthält.

  • Chrome Cache: Bei Änderungen an SSL/HSTS chrome://net-internals/#dns aufrufen und "Clear host cache" klicken.