nginx: Besucher mittels GeoIP2 nach Ländern blockieren (Geoblocking)

nginx Logo

Aus gegebenem Anlass soll es in diesem Artikel über das Blocken von Besuchern aus bestimmten Ländern mit dem Webserver nginx gehen.

Früher war dies recht einfach mittels GeoIP möglich: Dabei handelt es sich um eine von der Firma MaxMind gepflegte Datenbank mit Zuordnungen von IP-Adress-Bereichen zu den jeweiligen Ländern bzw. Städten. Diese Datenbank war lange Zeit frei verfügbar und konnte recht einfach in nginx eingebunden werden. Seit einiger Zeit gibt es jedoch das Nachfolge-Format GeoIP2, bei dem sich einiges geändert hat. GeoIP wird daher von MaxMind auch als ‚legacy‘ bezeichnet und im Mai 2022 wird der Support für dieses Format endgültig eingestellt (siehe MaxMind-Blog).

Nun lässt sich GeoIP2 leider nicht mehr so einfach nutzen wie das Legacy-Format. Daher zeit dieser Artikel alle notwendigen Schritte, die zum Einbinden von GeoIP2 in nginx notwendig sind und wie Website-Besucher aus bestimmten Ländern blockiert werden können.

Der Artikel basiert dabei auf Ubuntu Server 20.04 LTS und dem Webserver nginx, der aus den offiziellen Paketquellen von nginx installiert wurde. Auf diese Installation werde ich aber an dieser Stelle nicht weiter eingehen, dies wurde schon ein paar Mal in diesem Blog thematisiert, z.B. hier.

Update-Historie (letztes Update: 17.09.2022)
  • 17.09.2022:
    • Hinweis auf Script zum automatischen Aktualisieren des Moduls ngx_http_geoip2_module hinzugefügt.
  • 01.07.2022:
    • Hinweis bzgl. Updates nginx hinzugefügt.

Account bei MaxMind registrieren und Lizenz-Key erzeugen

Damit man die GeoIP2-Datenbanken herunterladen kann, ist ein Account bei MaxMind erforderlich. Ein solcher Account kann auf dieser Seite kostenlos erstellt werden, man benötigt dafür lediglich eine gültige E-Mail-Adresse.

Registrierung bei MaxMind
Registrierung bei MaxMind

Dazu klickt man einfach auf Sign Up for GeoLite2 und befolgt den Anweisungen der Anwendung. GeoLite2 ist übrigens das kostenlose Format von GeoIP2. Letzteres ist kostenpflichtig, wird aber häufiger aktualisiert. Weitere Informationen zu diesem Thema sind hier zu finden. Für unsere Zwecke reicht aber erst einmal das kostenlose Format GeoLite2.

Nach der Registrierung meldet man sich dann an der Webseite von MaxMind an und klickt auf der gleichen Seite wie oben schon erwähnt auf Generate a License Key. Dieser wird benötigt, damit man später vollkommen automatisiert Updates der Datenbanken abrufen kann.

Auch wenn wir später das Programm GeoIP Update nutzen werden, kann an dieser Stelle die Frage mit no beantwortet werden.

Einen neuen Lizenz-Schlüssel bei MaxMind erzeugen
Einen neuen Lizenz-Schlüssel bei MaxMind erzeugen

Im Anschluss wird die Account-ID und der Lizenz-Schlüssel selbst angezeigt. Diese Informationen bitte irgendwo speichern, da diese an dieser Stelle nur ein einziges Mal angezeigt werden und später auch nicht mehr eingesehen oder geändert werden können.

Account und Lizenz-Schlüssel nach der Erzeugung
Account und Lizenz-Schlüssel nach der Erzeugung

Nach diesen notwendigen Schritten können wir nun auf dem (Web-)Server per SSH weiter machen.

Installation des GeoIP Update Clients

Zum Herunterladen (und Updaten) der GeoIP-Datenbanken wird nun der GeoIP Update Client benötigt. Diesen (und weitere Abhängigkeiten) installieren wir aus dem offiziellen PPA:

add-apt-repository ppa:maxmind/ppa
apt update
apt install libmaxminddb0 libmaxminddb-dev mmdb-bin geoipupdate

Nun müssen noch die Lizenz-Daten im Programm konfiguriert werden:

nano /etc/GeoIP.conf 

Hier ist der Account und der Lizenz-Schlüssel anzugeben, der zuvor erzeugt wurde:

AccountID 123456
LicenseKey xxxxxxxxxxxxxxxx

# Enter the edition IDs of the databases you would like to update.
# Multiple edition IDs are separated by spaces.
EditionIDs GeoLite2-Country GeoLite2-City

Wenn keine Zuordnung von IP-Adressen zu Städten (sondern nur zu Ländern) benötigt wird, kann man hier noch den Eintrag GeoLite2-City entfernen.

Nun können auch schon die entsprechenden Datenbanken heruntergeladen werden:

geoipupdate -vvv

Nach einem kurzem Augenblick sollte der Vorgang erfolgreich abgeschlossen worden sein.

Nun richten wir noch einen Cronjob ein, der regelmäßig ein Update der Datenbanken herunter lädt und nginx anschließend neu lädt, damit der Webserver die aktualisierten Daten einlesen kann.

crontab -e

In diesem Beispiel wird der Cronjob jeden Sonntag um 03:15 ausgeführt:

15 3 * * 0 /usr/bin/geoipupdate && /bin/systemctl reload nginx.service > /dev/null 2>&1

nginx-Modul für GeoIP2 installieren

Nun muss nginx nur noch der Umgang mit GeoIP2 beigebracht werden. Dies geschieht durch das ein nginx-Modul, welches aber in der Standard-Installation nicht enthalten ist. Daher muss dieses zunächst einmal gebaut werden. Wir nutzen hier das Konzept von dynamischen Modulen, dies hat den Vorteil, dass nicht der ganze Webserver neu kompiliert werden muss, sondern nur das Modul selbst. Dieses wird dann später einfach dynamisch in die Webserver-Konfiguration eingebunden.

Zunächst installieren wir dazu wieder Abhängigkeiten und laden uns den Sourcecode des GeoIP2-Moduls herunter. Wichtig ist hier nur, dass wir uns den Pfad merken, in dem der Sourcecode liegt (hier beispielhaft unter /home/user/ngx_http_geoip2_module):

apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev libgd-dev libxml2 libxml2-dev uuid-dev libpcre3-dev
cd /home/user
git clone https://github.com/leev/ngx_http_geoip2_module.git

Als nächstes besorgen wir uns den Quellcode der bereits installierten nginx-Version:

NGINX_VERSION=$(nginx -v 2>&1|cut -d"/" -f 2)
wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz
tar zxvf nginx-$NGINX_VERSION.tar.gz
cd nginx-$NGINX_VERSION

Das GeoIP2-Modul wird nun folgendermaßen gebaut. Wichtig ist hier der Pfad zum Sourcecode des entsprechenden Moduls:

./configure --with-compat --add-dynamic-module=/home/user/ngx_http_geoip2_module
make modules
cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/ngx_http_geoip2_module.so

Ganz am Ende kopieren wir uns das erzeugte Modul noch in das Verzeichnis, aus dem nginx seine Module laden kann.

Hinweis: Diese Prozedur muss nach jedem Update von nginx wiederholt werden. Wird dies nicht gemacht, wird nginx nach einem Update nicht mehr starten können.

Um hier das Update nicht jedes Mal manuell vornehmen zu müssen, habe ich ein entsprechendes Script auf Codeberg zur Verfügung gestellt: update-ngx_http_geoip2_module

nginx-Konfiguration für GeoIP2

Für die Zusammenarbeit des GeoIP2-Moduls mit nginx muss nun noch die nginx-Konfiguration bearbeitet werden:

nano /etc/nginx/nginx.conf

Gleich in der ersten Zeile geben wir die Anweisung zum Laden des Moduls selbst:

load_module modules/ngx_http_geoip2_module.so;

In der gleichen Datei am Ende des http-Blocks (aber noch innerhalb dieses Blocks!) wird das Modul nun genutzt und konfiguriert:

geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
    $geoip2_data_country_iso_code country iso_code;
}

map $geoip2_data_country_iso_code $allowed_country {
   default yes;
   RU no;
}

Wichtig ist hier der letzte Block: Hiermit wird angegeben, dass der Zugriff auf die Website prinzipiell von überall aus möglich ist. Als einzige Ausnahme definieren wir nun Russland, so dass keine Zugriffe von russischen IPs mehr möglich ist.

Diese Logik lässt sich aber auch umkehren. Hier kann man als Standard jeglichen Zugriff unterbinden und dann einzelne Länder als Ausnahme hinzufügen. In diesem Fall würde der letzte Block dann so aussehen:

map $geoip2_data_country_iso_code $allowed_country {
   default no;
   DE yes;
   AT: yes;
   CH: yes;
}

In diesem Fall wäre später der Zugriff nur aus Deutschland, Österreich und der Schweiz möglich.

Die Ländercodes entsprechen hier dem Standard ISO-3166 (zweistellig). Eine Auflistung findet man dazu z.B. hier.

Hier wäre nun aber noch kein Filter o.ä. implementiert. Dazu bedarf es noch der Anpassungen des virtuellen Hosts der jeweiligen Webanwendung:

nano /etc/nginx/conf.d/meinedomain.de.conf

Hier fügt man nun einfach innerhalb des server-Blocks folgende Anweisung ein:

if ($allowed_country = no) {
	 return 444;
}

Wenn das Land des Website-Besuchers also nicht als „allowed_contry“ betrachtet wird, liefert der Webserver einen HTTP 444 Fehler als Antwort zurück – also einfach „No Response“. Hier werden dann nicht mal Header o.ä. übertragen. Es wäre aber auch denkbar, einen HTTP 403 („Forbidden“) oder HTTP 451 („Unavailable For Legal Reasons“) zurück zu liefern (siehe Liste der HTTP-Statuscodes).

Am Ende fehlt nur noch ein Neustart des Webservers:

service nginx restart

Wird nun die jeweilige Webseite aus einem „geblockten Land“ aufgerufen, erscheint nur eine Fehlermeldung im Browser:

HTTP 444 Fehler auf einer Website
HTTP 444 Fehler auf einer Website

Fazit

Mit den hier gezeigten Schritten kann auf einfache Weise ein Geoblocking mit nginx umgesetzt werden.

Zum Schluss aber noch ein wichtiger Hinweis: Auch wenn der Zugriff aus einigen Ländern damit unterbunden wird, gilt es jedoch zwei Dinge zu beachten:

  • IP-Adress-Bereiche können mal schnell den Besitzer (und damit ggf. auch das Land) wechseln. Hier kommt es dann immer auf die Aktualität der GeoIP2-Datenbank an bzw. ob der Hersteller hier immer eine korrekte Zuordnung vornimmt. Es kann passieren, dass diese Zuordnungen nicht immer zu 100% korrekt sind.
  • Viel wichtiger: Versierte Anwender, Organisationen und Behörden wird man mit der hier gezeigten Methode kaum effektiv davon abhalten können, Inhalte der entsprechenden Webseiten abzurufen. Beispielsweise kann man dieses Geoblocking einfach umgehen, indem man einen VPN-Dienst aus einem anderen Land nutzt.

Aus diesen Gründen ist die hier gezeigte Variante zwar ein guter erster Schritt, wenn es um das Geoblocking geht, man sollte sich aber niemals darauf verlassen.

Dieser Blog ist ja seit jeher unpolitisch. Trotzdem möchte ich noch einmal die aktuelle Situation auffassen. Meine volle Solidarität gilt dabei der Ukraine! Hier sollte man aber dennoch nicht vergessen, dass diese Aggression von einigen wenigen Personen ausgeht. Es sind nicht „die Russen“, die diesen Krieg zu verantworten haben. Ich bin davon überzeugt, dass die Mehrheit des russischen Volkes nicht hinter dieser weitreichenden Entscheidung steht.
Durch ein Geoblocking Russlands trifft man daher vermutlich nicht diejenigen, die diesen Krieg zu verantworten haben, sondern v.a. Leute, die so sind wie „du und ich“ – Menschen, die einfach nur in Frieden leben wollen.

In diesem Sinne: Make love, not war!

Links

49 Kommentare zu „nginx: Besucher mittels GeoIP2 nach Ländern blockieren (Geoblocking)“

  1. Hi Jan,
    bei all-inkl.com kann man es wie folgt einrichten:

    GeoIPEnable On
    SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry
    SetEnvIf GEOIP_COUNTRY_CODE A1 BlockCountry
    SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry
    Deny from env=BlockCountry

    Alles in die .htaccess und zum Test mal DE einrichten, um den Schutz zu testen :-)
    Der Eintrag „A1“ schliesst „anonymous Proxy Verbindungen (bspw. Satelliten Verbindungen etc…) aus.

    Grüße, Carsten (c-rieger.de)

    1. Hi Carsten,

      danke für den Hinweis.
      Man braucht aber nicht unbedingt mal „DE“ in die Block-Liste mit aufzunehmen. Das Ansurfen mit einem russischen Proxy (siehe z.B. hier) sollte eine entsprechende Fehlermeldung ausgeben.

      Gruß,
      Jan

  2. Hallo Jan,
    erhalte folgende Meldung beim Kompilieren.
    checking for OS
    + Linux 5.4.0-100-generic x86_64
    checking for C compiler … not found

    ./configure: error: C compiler cc is not found
    Welcher Compiler wird hier benötigt?

    Danke

    Gruß Hans

    1. Hi Hans,

      oh, da fehlen wohl noch die Dev-Dependencies. Kannst du diese mal mit apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev libgd-dev libxml2 libxml2-dev uuid-dev installieren und es dann nochmals probieren?
      Bitte um kurze Rückmeldung, dann würde ich das noch im Artikel ergänzen.

      Gruß,
      Jan

  3. Hallo,
    danke für den Artikel.
    Ich nutze die Variante:
    “ map $geoip2_data_country_iso_code $allowed_country {
    default no; “
    Über mein PiHole leite ich Domainanfragen auf die interne IP der Nextcloud. Leider blockt GeoIP interne Anfragen, weil diese logisch keine Länderkennung haben. Gibt es eine Möglichkeit eine Ausnahme für die gesamte interne IP Range (bspw. 192.xxx.xxx.0/24) in einem der Scripte zu etablieren? Welche Stelle wäre elegant?

    Danke
    VG

    1. Hallo Horst,

      das habe ich noch nicht ausprobiert, aber funktioniert es vielleicht, wenn du dort, wo default no; noch 192.168.178.0/24 yes; hinzufügst?
      Ansonsten eine zweite Map einfügen:
      geo $lan-ip {
      default no;
      192.168.178.0/24 yes;
      }

      Und dann vor dieser Abfrage:
      if ($allowed_country = no) {
      return 444;
      }

      Noch folgende Abfrage einfügen:
      if ($lan-ip = yes) {
      set $allowed_country yes;
      }

      So müsste dies dann denke ich gehen.

      Gruß,
      Jan

      1. Hallo Jan,

        danke für die Tipps.
        Der erste Vorschlag hat leider nicht geklappt aber der zweite Funktioniert super.

        Vielen Dank

        Viele Grüße
        Horst

        1. Hi Horst,

          super, danke für die Rückmeldung. Werde ich mir gleich mal notieren, falls die Frage nochmal aufkommen sollte.

          Gruß,
          Jan

      2. Hi,

        wäre schön, wenn jemand das nochmal genauer aus führen würde, denn ich würde gerne das bei mir installieren.
        Leider habe ich auch das Problem, dass ich intern nicht mehr auf meine Nextcloud zugreifen kann.

        Aus keinem meinen internen Netzen
        192.168.10.0 /24
        192.168.1.0 /24

        Habe alles so eingerichtet wie hier in der Grundanleitung angegeben, nur wollte ich alles sperren außer Deutschland da ich es nur für mich und Family nutze,

        Würde mich für Hilfe bedanken,

        1. Hi Thomas,

          bei dir wäre das dann vermutlich so:
          geo $lan-ip {
          default no;
          192.168.10.0/24 yes;
          192.168.1.0/24 yes;
          }

          Und dann bei der Abfrage selbst:
          if ($lan-ip = yes) {
          set $allowed_country yes;
          }

          if ($allowed_country = no) {
          return 444;
          }

          Die Abfrage auf $allowed_country muss zwingend nach der Abfrage auf $lan-ip kommen.

          Gruß,
          Jan

          1. Hi Jan,

            wie immer schnelle Antwort :-) Danke.

            Nur für die Doofen, also für mich kommt die Abfrage in die
            nano /etc/nginx/nginx.conf
            Anstatt, was in der Anleitung steht?
            oder
            nano /etc/nginx/conf.d/meinedomain.de.conf

            Ich weiß wahrscheinlich eine dumme Frage, aber hatte es gestern Nacht versucht aber irgendwie ist dann immer service nginx restart nicht mehr gestartet.

            Irgendwie mache ich da was falsch, denn mit der Grundkonfiguration, konnte ich via Handynetz immer zugreifen.
            Vielleicht erklärst Du mir das wie einem 5 Jährigen, :-)

            Gruß
            Thomas

          2. Hi Thomas,

            ja, das kommt in die /etc/nginx/nginx.conf
            Das Einbinden des Moduls selbst nicht vergessen!

            Wenn nginx nicht mehr startet, kannst du über „nginx -t“ herausfinden, an was er sich da stört.

            Gruß,
            Jan

          3. Hi Jan,

            danke für die Info, jedoch klappt es nicht und ich erhalte beim Start von nginx immer noch eine FM.

            nginx -t
            nginx: [emerg] „if“ directive is not allowed here in /etc/nginx/nginx.conf:50
            nginx: configuration file /etc/nginx/nginx.conf test failed

            Meine Eintragungen sehen wie folgt aus:

            geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
            $geoip2_data_country_iso_code country iso_code;
            }

            map $geoip2_data_country_iso_code $allowed_country {

            default no;
            DE yes;
            RU no;
            }
            geo $lan-ip {
            default no;
            192.168.10.0/24 yes;
            192.168.1.0/24 yes;
            }

            if ($lan-ip = yes) {
            set $allowed_country yes;
            }

            if ($allowed_country = no) {
            return 444;
            }
            }

          4. Hi Thomas,

            was steht denn genau in Zeile 50?
            Die Meldung kommt eigentlich immer dann, wenn man if-Statements verschachtelt, denn das unterstützt nginx nicht.

            Gruß,
            Jan

          5. Hi Jan,

            also es steht in der Zeile 50

            if ($lan-ip = yes) {

            Da meine nginx nicht so groß ist, mal den gesamten Inhalt

            load_module modules/ngx_http_geoip2_module.so;
            user www-data;
            worker_processes auto;

            error_log /var/log/nginx/error.log notice;
            pid /var/run/nginx.pid;

            events {
            worker_connections 1024;
            }

            http {
            include /etc/nginx/mime.types;
            default_type application/octet-stream;

            log_format main ‚$remote_addr – $remote_user [$time_local] „$request“ ‚
            ‚$status $body_bytes_sent „$http_referer“ ‚
            ‚“$http_user_agent“ „$http_x_forwarded_for“‚;

            access_log /var/log/nginx/access.log main;

            sendfile on;
            #tcp_nopush on;

            keepalive_timeout 65;

            #gzip on;
            server_tokens off;
            include /etc/nginx/conf.d/*.conf;

            geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
            $geoip2_data_country_iso_code country iso_code;
            }

            map $geoip2_data_country_iso_code $allowed_country {

            default no;
            DE yes;
            RU no;
            }
            geo $lan-ip {
            default no;
            192.168.10.0/24 yes;
            192.168.1.0/24 yes;
            }

            if ($lan-ip = yes) {
            set $allowed_country yes;
            }

            if ($allowed_country = no) {
            return 444;
            }
            }

          6. Hi Thomas,

            diese Zeitle hier sieht komisch aus: geo $lan-ip {

            Probier hier mal ein

            map $remote_addr $lan-ip {

            Gruß,
            Jan

          7. Hi Jan,

            habe es probiert, jetzt hat er mit der if Abfrage ein Problem.

            if ($lan-ip = yes) {
            set $allowed_country yes;
            }

            nginx: [emerg] „if“ directive is not allowed here in /etc/nginx/nginx.conf:51
            nginx: configuration file /etc/nginx/nginx.conf test failed

            Hast Du noch eine Idee ?

            Gruß

            Thomas

          8. Hi Thomas,

            ah, das ist in der nginx.conf, oder?
            if-Blöcke sind aber nur in server- oder location-Blöcken erlaubt. Zieh daher mal diese beiden if-Bedingungen in einen server-Block, also vermutlich irgendwas unter /etc/nginx/conf.d/irgendwas.de.conf.

            Gruß,
            Jan

    2. Hallo Jan,

      leider hat es nicht geklappt, denke, das funktioniert irgendwie nicht im eigenen Netz, wenn ich das über den Namen nextcloud.domäne.de aufrufe.

      Aber Sicherheitshalber nochmal meine Blöcke:

      /etc/nginx/conf.d/irgendwas.de.conf

      if ($lan-ip = yes) {
      set $allowed_country yes;
      }

      if ($allowed_country = no) {
      return 444;

      }

      /etc/nginx/nginx.conf

      geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
      $geoip2_data_country_iso_code country iso_code;
      }

      map $geoip2_data_country_iso_code $allowed_country {
      default no;
      DE yes;
      }

      map $remote_addr $lan-ip {
      192.168.10.0/24 yes;
      192.168.1.0/24 yes;
      }

      1. Hi Thomas,

        weil du schreibst, dass du über die NC-Domain zugreifst: Ich gehe davon aus, dass die NC lokal bei dir läuft (192.168.10.xxx). Wenn nun einen Ping auf die NC-Domain aus deinem LAN machst, welche IP wird hier angezeigt? Wenn das die WAN-IP ist, dann geht der Request „über das Internet“ und daher greift die Abfrage auf LAN-IP nicht.
        Die Clients müssen die NC-Domain mit der 192.168.10.xxx auflösen. Wenn das nicht der Fall ist, dann hilft vermutlich nur ein eigener DNS-Server, der die DNS-Einträge auf die LAN-IPs umbiegt.

        Gruß,
        Jan

        1. Hallo Jan,

          ja, Du hast recht, wenn ich meine Nextcloud an pinge bekomme ich die öffentliche IP-Adresse zurück.
          Habe das mal mit meinem Windows DNS auf meinem Windows Domäne versucht, aber da ich zu Hause nur eine Domäne.local nutze, klappt das mit dem Alias irgendwie nicht, da auch die beiden Domänen nicht gleich sind.

          Habe jetzt folgendes gemacht:

          map $geoip2_data_country_iso_code $allowed_country {
          default no;
          DE yes;
          ‚ ‚ yes;

          Na zumindest funktioniert es, hast Du eine Idee wie man die Variable Auslesen kann und vielleicht in eine Datei schreiben kann. Denn würde mal wissen was da genau drin steht, denke, die ist nach meinem wissen leer, weil er keine Länderzuordnung findet bei mir.

          1. Hi Thomas,

            in deinem Code wird denke ich etwas nicht korrekt angezeigt, das sieht irgendwie komisch aus (liegt vermutlich daran, dass in der Kommentar-Funktion einige Sachen automatisch interpretiert werden und ggf. rausfliegen).

            Mit dem DNS meinte ich das übrigens anders: Du musst den Rechner nicht in die Windows-Domäne hängen, sondern brauchst nur einen DNS-Server, der im LAN deine (echte) Cloud-Domain mit der LAN-IP des Rechners verknüpfst. Wenn du dann beispielsweise meinedomain.de im LAN aufrufst (oder anpingst), dann wird die Domain auf z.B. 192.168.178.xxx aufgelöst. Extern macht das dann ein „normaler“ DNS-Server, da löst die Domain auf deine öffentliche IP-Adresse auf.

            Gruß,
            Jan

          2. Hallo Jan,

            ich denke ich hatte Dich richtig verstanden, jedoch habe ich mich vielleicht doof ausgedrückt.

            Meine config sieht eigentlich so aus:

            Ich habe bereits eine Domainname.local und in der werden für alle Rechner die Zugriffe geregelt (Fileservice / Druckerdienste / Richtlinien)
            Als Dienst läuft bzw. muss auch ein DNS-Dienst laufen, sonst funktioniert die Domäne ja nicht.
            Natürlich kann ich mittels IP auf den NC zugreifen, aber da ich auch Laptops, Handys nutzen müsste ich mit FQDN auf die NC zugreifen,
            Was natürlich vorher einfach geklappt hat, nur jetzt, warum auch immer erkennt er nicht, dass ich mit einer Deutschen IP zugreife.
            Jetzt dachte ich nun aufgrund Deines Vorschlags, ich mache einen Alias Eintrag im DNS und verweise auf die IP-Adresse. Aber das funktioniert nicht, da die Domänen dann verschieden sind.
            Dann habe ich mal aus Spaß bzw. Neugier mal getestet ob wenn ich auf ein leeres Feld prüfe, ob das funktioniert. “ “
            Scheinbar ist das so, dass, wenn GeoIP2 kein passendes Land in seiner Datenbank findet, er ein leeres zurückgibt.
            Aber genau weiß ich das nicht, zumindest wenn ich DE rausnehme wird es sofort geblockt in dieser Konstellation.
            Deshalb wollte ich gerne wissen, wie man bei Zugriff diese Variable auslesen kann und vielleicht speichern kann, um zu sehen, was er so treibt.
            Ich bin auf Linux halt ein voll Noob und lerne eigentlich durch Deine Veröffentlichungen. Da hier nicht nur erklärt, wie man es macht, sondern auch warum. Man kann es nicht zu oft sagen, das ist hier schon großes Kino :-) Profi

            Danke für alles und hoffe, Du hörst nie auf……..

          3. Hi Thomas,

            wenn das mit der lokalen DNS-Auflösung funktioniert, kommst du mit einer LAN-IP (z.B. 192.168.178.100) „bei deiner Cloud an“. Diese IP (da lokal), kann gar nicht einem Land zugeordnet werden. Daher wird denke ich einfach geblockt. Daher erst die Abfrage auf Geo-IP und anschließend die Variable (allowed_country) noch mit ‚yes‘ überschreiben, wenn es sich im eine LAN-IP handelt (siehe einige Kommentare weiter oben).

            „Debuggen“ kann man eine nginx Config leider nicht so richtig, es gibt zwar ein Conditional Logging, aber das würde die Sache sehr viel komplizierter machen. Daher würde ich damit ehrlich gesagt gar nicht erst anfangen.

            Gruß,
            Jan

  4. Hallo Jan,

    weil ich in einer anderen Anleitung von dir gerade etwas nachschauen musste, bin ich auch auf diese Anleitung aufmerksam geworden. Wie immer eine super und zudem zeitgemäße Anleitung.

    Ich musste ebenfalls ein Geoblocking einführen, da mein Mailserver seit 25.02. massiv aus China angegriffen wurde. Der Angriff war nachweisbar auf das Vorhandensein von Standard-fail2ban-Regeln ausgelegt. Da fail2ban standardmäßig nach 3 Angriffen für 10 min blockt, wurden immer 3 Angriffe protokolliert und dann geblockt. fail2ban hat sich also absolut bezahlt gemacht und perfekt funktioniert. Aber der Angreifer hatte ein unfassbare Anzahl an unterschiedlichen öffentlichen IPs zur Verfügung, so dass er einfach eine andere IP genutzt hat, um den Block durch fail2ban für 3 weitere Versuche zu umgehen. Der schwerste Angriff, der bisher bei mir protokolliert wurde. Aber! Die Sicherungsmaßnahmen haben gegriffen und funktioniert. Es gab nur eine erschreckend lange Liste an Mails, die die Angriffe gemeldet haben.

    Da ich nicht gleich eine für mich zufriedenstellende Lösung gefunden habe, habe ich den Angriff zunächst laufen lassen. Unfassbare 228 Angriffe innerhalb von 19 Stunden sind so entstanden und fast alle mit anderen öffentlichen IPs, fast ausschließlich aus China. Nur 2 oder 3 wurden mit dem selben Muster über Australien geleitet. Erst mit dem Anschalten meiner Geoblocking-Lösung hatte das bereits ein Ende an der Firewall. Wer fail2ban nutzt, sollte sich definitiv auch einmal mit longterm-Regeln für fail2ban beschäftigen. Die Standard-Regeln lassen sehr schön erkennen, dass viele Angreifer die Regeln kennen und ihre Mechanismen darauf abstimmen. Dann kommt halt alle 11 Minuten ein Angriff um wieder 3 Möglichkeiten des Zugangs getestet zu haben. Eine zusätzliche longterm-Regel schadet nicht. In etwa so: 10 Angriffe in einem sehr deutlich längeren Suchzeitraum führen zu einer extrem langen oder endgültigen Sperrung über fail2ban. Das allein sorgt schon für eine deutlich kürzere Mailbenachrichtigungsliste. Zudem sind IP-Blacklisten hilfreich um ganze IP-Adressbereiche ausschließen zu können. Hilft aber eben alles leider nicht mehr, wenn die IP-Adressen jedes mal komplett wechseln. Dann muss Geoblocking als nächst höhere Stufe her.

    Ich habe den Geoblock jetzt über ein Script mit ipset, IP-Listen von ipdeny.com und iptables gelöst. So musste ich mich notgedrungen mit der Firewall beschäftigen, was vorher nicht nötig war. Bisher war ufw meine Möglichkeit iptables zu konfigurieren. Aber, wie es dann immer ist: Blöde Situation, aber wieder etwas gelernt.

    Was ich am Ende damit sagen will: Es ist ZWINGEND erforderlich das selbstgehostete System auch abzusichern und zu wissen, was man mit der Öffnung von Ports nach außen anrichten kann. Man ist nie zu unbedeutend, um nicht angegriffen zu werden. Wirklich sichere Passworte, Kenntnisse im Umgang mit Firewalls und extrem hilfreichen Tools wie fail2ban sind ein MUSS. Wer mit laufendem fail2ban mal Port 22 (ssh) offen hatte, weiß wovon ich hier rede.
    Zudem sollte man auch wissen, dass ein abgewehrter Angriff super ist, aber der Angreifer trotzdem die Möglichkeit hatte Dinge zu testen und damit zu wissen, was schon mal nicht funktioniert hat. Ich bin mir sicher, dieser extrem massive Angriff hat zwar keinen Erfolg bei mir gehabt, aber es existiert jetzt eine Datenbank mit 684 Versuchen, die man nicht mehr testen braucht, weil sie schon als erfolglos gekennzeichnet sind. Und so geht das Ganze immer weiter.

    Grüße Steffen

    1. Hi Steffen,

      danke für deine ausführlichen Erläuterungen.
      Und ja, auch wenn man nur einen „kleinen Server“ betreibt, bleiben die Angriffe leider nicht aus. Port 22 für SSH nutze ich schon lange nicht mehr (auch wenn die Port-Änderung hier keine echte Sicherheits-Maßnahme bedeutet!). Zu deiner Liste an Maßnahmen möchte ich noch hinzufügen, dass man den SSH-Zugriff ausschließlich mittels SSH-Key durchführen kann (und die Authentifizierung mittels User/Passwort komplett deaktivieren kann).
      Für Dienste wie z.B. Nextcloud kommt dann noch die Authentifizierung mittels Two-Factor dazu.

      Gruß,
      Jan

  5. Hallo Jan,
    vielen Dank für deine immer wieder inspirierenden und tollen Beiträge. Da ich mich für Apache2 entschieden habe, muss ich immer ein wenig umdenken, geht aber fast immer. Nun habe ich eine Herausforderung, die ich nicht gelöst bekomme:
    Meine Länderkennungen sind leider nicht immer korrekt. Heute zum Beispiel soll ich angeblich aus der UE kommen, obwohl ich über einen deutschen Provider auf meinen Server gehe. Bei mehreren Whois Anbietern meine IP geprüft, alles DE. Bei https://www.maxmind.com/en/locate-my-ip-address meine IP geprüft, ist DE. Wenn ich jetzt per PHP meine Länderkennung ausgeben lasse, um zu sehen warum ich geblockt bin, steht da UE. Ab hier bin ich ratlos, hast du vielleicht eine Idee? Habe Updates der Datenbank wie von dir beschrieben gemacht, läuft ohne Fehler. Neustart Server bringt nichts.
    Viele Grüße
    Norry

    1. Hi Norry,

      außer ein Update der GeoIP-DB sehe ich hier aktuell keine Möglichkeit.
      IPv4 Adressen sind halt nicht per se Standort-bezogen. Durch den extremen Mangel an IPv4-Adressen kann es auch mal passieren, dass IPs verkauft werden und von anderen Unternehmen verwendet werden, die einen ganz anderen Standort nutzen. Hier kann man dann nur hoffen, dass es in der GeoIP-DB möglichst schnell nachgezogen wird.
      UA ist übrigens die Ukraine, wer weiß, was da momentan Internet-technisch so abgeht…

      Gruß,
      Jan

      1. Hallo Jan,
        vielen Dank für die Rückmeldung. Hab geupdatet bis die Finger blutetten, bin zum Schluss gekommen, dass die freie DB nicht so gut ist, schreiben die auch. Mal komme ich aus USA dann aus UE, dann wieder aus DE.
        Liegt wahrscheinlich an meinem Provider, muss ich mit leben.
        Gruß
        Norry

        1. Hi Norry,

          ja, „kostenlos“ hat ja meist einen Haken. Frage wäre natürlich, wie hoch der Prozentsatz der „false positives“ mit der kostenlosen Variante ist. Falls ich hier noch Erkenntnisse sammeln kann, werde ich den Artikel entsprechend ergänzen.

          Gruß,
          Jan

  6. Hallo Jan,
    ich erhalte beim Starten vom nginx folgende Fehlermeldung:

    nginx.service – nginx – high performance web server
    Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
    Active: failed (Result: exit-code) since Thu 2022-03-31 01:36:33 CEST; 8min ago
    Docs: https://nginx.org/en/docs/
    Process: 2946231 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)

    Mar 31 01:36:33 systemd[1]: Starting nginx – high performance web server…
    Mar 31 01:36:33 nginx[2946231]: nginx: [emerg] MMDB_open(„/usr/share/GeoIP/GeoLite2-Country.mmdb“) failed – Error opening the specified MaxMind DB file>/GeoIP/GeoLite2-Country.mmdb“) failed – Error opening the specified MaxMind DB file in /etc/nginx/nginx.conf:37
    Mar 31 01:36:33 systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
    Mar 31 01:36:33 systemd[1]: nginx.service: Failed with result ‚exit-code‘.
    Mar 31 01:36:33 systemd[1]: Failed to start nginx – high performance web server.

    Hast du eine Idee, was da schief gelaufen sein kann?

    Ich danke dir schon einmal vielmals für deine Hilfe :)

    Viele Grüße

    Luca

      1. Hi Jan,

        genau, ich habe das im nginx das GeoIP2 Modul installiert. Es ist mir da nicht aufgefallen, ob es zu Fehlern gekommen ist. Die Installation ist durchgelaufen.
        Tatsächlich musste ich bei mir folgenden Pfad anpassen:
        /usr/share/GeoIP/GeoLite2-Country.mmdb
        Der war bei mir woanders abgelegt worden bei der Installation.

        Funktioniert nun alles wunderbar :)

        Vielen Dank

  7. Hi Jan,

    ich betreibe einen ubuntu 20.04 nextcloud-Server gemäß Deinen Empfehlungen und habe auch versucht, das Geo-Blocking zu installieren.
    Alle Schritte liefen fehlerfrei durch, alle Änderungen habe ich mehrfach geprüft. Jedoch habe ich den Eindruck, das Blocken funktioniert bei mir einfach nicht. Aktiviere ich an meinem Smartphone (nur mittels mobilen Daten online) eine VPN Verbindung über einen ausländischen Server, kann ich trotzdem meine Nextcloud-Startseite aufrufen. Das habe ich mit verschiedenen Ländern ohne Erfolg getestet.
    Wie kann ich da vorgehen, um den Fehler zu finden?
    Viele Grüße,
    Matthias

    1. Hallo Matthias,

      das wird leider etwas schwierig. Zunächst einmal ist mir kein Weg bekannt, mal eben schnell eine spezifische IP in der GeoIP-Datenbank nachzuschlagen, welchem Land diese zugeordnet wird.
      Ich würde vermutlich mal das eigene Land komplett blockieren und dann nachsehen, ob es immer noch nicht funktioniert. Hier hilft dann evtl. ein Blick in die nginx-Logs.

      Gruß,
      Jan

      1. Hi Jan, danke für die schnelle Antwort.

        Folgendes habe ich noch getestet:
        * in der nginx.conf: default no und DE no gesetzt.
        * die Datenbank von Maxmind aktualisiert – keine Fehler
        * nginx dienst neu gestartet
        * in der nginx log finde ich keine Unauffälligkeiten – allerdings auch keine Hinweise, dass das GeoIP Modul irgendwelche Variablen schreibt
        – der Zugriff mittels einer deutschen IP ist immer noch möglich.

        1. Hi Matthias,

          ok, dann funktioniert vermutlich das ganze Geo-Modul von nginx nicht richtig. Hast du mal bei Bauen des Moduls darauf geachtet, ob hier irgendwelche Fehlermeldung gekommen sind. Manchmal sieht ein Build auf den ersten Blick so aus, als ob alles korrekt war, wenn man aber genau hinsieht, bemerkt man hier und da einen Fehler. Dann funktioniert das gebaute Programm meistens nicht.
          Also an deiner Stelle würde ich das Bauen des Moduls wiederholen und genau auf Fehler/Warnungen achten.

          Gruß,
          Jan

    1. Hi Hans,

      das ist die „integrierte“ Version, oder? Gilt das gleiche auch für die Docker-Variante von Collabora?
      Kannst du irgendwie heraus finden, beim Aufruf welcher URL er diesen Fehler meldet?

      Gruß,
      Jan

      1. Hallo Jan,
        ja bei der intergierten Version. Wenn ich die Einträge in der nginx.conf und meinedomain.de.conf rausnehme und nginx neu starte funktiniert es wieder.

        In den Log´s finde ich hierzu keine IP.
        Docker teste ich noch und gebe dir dann Bescheid.
        Gruß Hans

    1. Hi Hans,

      erst einmal danke für deine Test!
      Bei OnlyOffice kann ich das allerdings nicht nachvollziehen. Hier mache ich auf meinen Instanzen auch einen Geo-Block, aber OnlyOffice (Docker) läuft nach wie vor ohne Probleme. Daher denke ich, dass es ein grundsätzliches Problem ist.

      Gruß,
      Jan

  8. Hallo Jan,

    wo genau kommt der Block rein, damit Push noch funktioniert?

    if ($allowed_country = no) {
    return 444;
    }

    Wenn ich den Block unterhalb von “ server { listen 443 ssl http2;listen [::]:443 ssl http2;“ einfüge erhalte ich folgende Meldung beim Ausführen von sudo -u www-data php occ notify_push:setup

    Fehler:
    Push binary seems to be running already
    🗴 failed to run self-test.
    test output: ✓ redis is configured
    🗴 using unencrypted http for push server is strongly discouraged
    🗴 push server url is set to localhost, the push server will not be reachable from other machines
    ✓ push server is receiving redis messages
    ✓ push server can load mount info from database
    🗴 push server can’t connect to the Nextcloud server

    Nehme ich den Block komplett raus, funktioniert Push.
    Wenn ich diesen in der HttpGateway.conf einfüge, funktioniert GeoIP nartürlich nicht.
    Wenn ich den Block unterhalb von “ server { listen 443 ssl http2;listen [::]:443 ssl http2;“ einfüge funktioniert Push nicht mehr.

    Vielen Dank

    Gruß Hans

    1. Hi Hans,

      der Block ist bei mit direkt im Server-Block für NC enthalten (direkt oberhalb von # Include SSL configuration). Damit funktioniert das Push bei mir.

      Gruß,
      Jan

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert