So erstellen Sie eine Discourse-Installation mit einem Open-Source-WAF

Ich darf in „How-Tos“ keine Beiträge verfassen, also poste ich dies hier :slight_smile:

Übersicht

Das Ziel ist es, eine WAF (Web Application Firewall) zu bestehenden Ressourcen hinzuzufügen, ohne die Leistung bei einer kleinen Installation zu beeinträchtigen. In diesem Beispiel verwenden wir eine einzelne EC2-Instanz. Da Discourse in Docker läuft, können wir NGINX auf dem Host installieren und per Proxy-Pass den Verkehr in unseren Docker-Container leiten. Zudem nutzen wir RDS für PostgreSQL.

Discourse-Konfiguration

Unser erster Schritt besteht darin, die Datei app.yml für eine benutzerdefinierte Discourse-Installation zu konfigurieren. In diesem Beispiel führen wir die Rollen „web“ und „redis“ aus. Wir verwenden weder die DB-Rolle noch die SSL-Rollen.

Außerdem möchten wir sicherstellen, dass wir keine Web-Ports im Docker-Container exponieren. Der Grund dafür ist, dass wir den Webzugriff über den NGINX-Proxy auf dem Host bereitstellen.

Beispiel für eine app.yml-Datei

## Dies ist die All-in-One-Standalone-Discourse-Docker-Container-Vorlage
##
## Nach Änderungen an dieser Datei MUSS neu erstellt werden:
## /var/discourse/launcher rebuild app
##
## SEHR VORSICHT BEI DER BEARBEITUNG!
## YAML-DATEIEN SIND EXTREM EMPFINDLICH GEGENÜBER FEHLERN IN LEERZEICHEN ODER AUSRICHTUNG!
## Besuchen Sie http://www.yamllint.com/, um diese Datei bei Bedarf zu validieren
templates:
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
## Kommentieren Sie diese beiden Zeilen aus, wenn Sie Lets Encrypt (https) hinzufügen möchten
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"


## Welche TCP/IP-Ports soll dieser Container exponieren?
## Wenn Sie Discourse einen Port mit einem anderen Webserver wie Apache oder nginx teilen möchten,
## siehe https://meta.discourse.org/t/17247 für Details
expose:
#  - "80:80"   # http
#  - "443:443" # https


params:
  db_default_text_search_config: "pg_catalog.english"
  ## Setzen Sie db_shared_buffers auf maximal 25 % des gesamten Arbeitsspeichers.
  ## Wird automatisch vom Bootstrap basierend auf dem erkannten RAM gesetzt oder Sie können überschreiben
  db_shared_buffers: "768MB"
  ## Kann die Sortierleistung verbessern, erhöht jedoch den Speicherverbrauch pro Verbindung
  #db_work_mem: "40MB"
  ## Welchen Git-Revision soll dieser Container verwenden? (Standard: tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en
  ## Wie viele gleichzeitige Webanfragen werden unterstützt? Hängt vom Arbeitsspeicher und den CPU-Kernen ab.
  ## Wird automatisch vom Bootstrap basierend auf den erkannten CPUs gesetzt oder Sie können überschreiben
  UNICORN_WORKERS: 2

  ## TODO: Der Domainname, auf den diese Discourse-Instanz antworten soll
  ## Erforderlich. Discourse funktioniert nicht mit einer reinen IP-Nummer.
  DISCOURSE_HOSTNAME: cloudforums.net

  ## Kommentieren Sie dies aus, wenn Sie möchten, dass der Container mit dem gleichen
  ## Hostnamen (-h-Option) wie oben angegeben gestartet wird (Standard: „$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: Liste der durch Komma getrennten E-Mail-Adressen, die bei der ersten Registrierung zu Administratoren und Entwicklern werden
  ## Beispiel: 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'youremail@domain.com'

  ## TODO: Der SMTP-Mailserver, der zur Validierung neuer Konten und zum Senden von Benachrichtigungen verwendet wird
  ## SMTP-Adresse, Benutzername und Passwort sind erforderlich
  ## WARNUNG: Das Zeichen '#' im SMTP-Passwort kann Probleme verursachen!
  DISCOURSE_SMTP_ADDRESS: YOUR_SMTP
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: YOUR_SMTP_USERNAME
  DISCOURSE_SMTP_PASSWORD: YOUR_SMTP_PASSWORD
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, Standard: true)

  ## Wenn Sie die Lets Encrypt-Vorlage hinzugefügt haben, kommentieren Sie unten aus, um ein kostenloses SSL-Zertifikat zu erhalten
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  DISCOURSE_DB_SOCKET: ''
  DISCOURSE_DB_USERNAME: YOUR_USERNAME
  DISCOURSE_DB_PASSWORD: YOUR_PASSWORD
  DISCOURSE_DB_HOST: YOUR_HOST

  ## Die HTTP- oder HTTPS-CDN-Adresse für diese Discourse-Instanz (konfiguriert zum Abrufen)
  ## siehe https://meta.discourse.org/t/14857 für Details
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com
## Der Docker-Container ist zustandslos; alle Daten werden in /shared gespeichert
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins gehen hier
## siehe https://meta.discourse.org/t/19157 für Details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## Beliebige benutzerdefinierte Befehle, die nach dem Erstellen ausgeführt werden sollen
run:
  - exec: echo „Beginn der benutzerdefinierten Befehle"
  ## Wenn Sie die Absender-E-Mail-Adresse für Ihre erste Registrierung festlegen möchten, kommentieren Sie dies aus und ändern Sie:
  ## Nachdem Sie die erste Anmelde-E-Mail erhalten haben, kommentieren Sie die Zeile erneut aus. Sie muss nur einmal ausgeführt werden.
  - exec: rails c „SiteSetting.enable_badge_sql = true"
  - exec: echo „Ende der benutzerdefinierten Befehle"

Beginn der Discourse-Installation

Discourse-Repository klonen

sudo -u root git clone https://github.com/discourse/discourse_docker.git /var/discours

Benutzerdefinierte app.yml für die Installation kopieren

Sie können den folgenden Befehl ausführen, um dies für Sie zu erledigen. Ersetzen Sie einfach den Testtext „PASTE YOUR FULL APP.YML HERE“ durch Ihre vollständige app.yml.

sudo -u root cat > /var/discourse/containers/app.yml <<\EOF
PASTE YOUR FULL APP.YML HERE
EOF

Discourse-Setup ausführen

Starten Sie das Discourse-Setup ohne Aufforderungen mit dem folgenden Befehl.

sudo -u yes "" | /var/discourse/./discourse-setup

Die Discourse-Installation sollte etwa 10–15 Minuten dauern.

NGINX-, WAF- und GEOIP-Installation

Updates ausführen und Voraussetzungen installieren

apt update -y
apt upgrade -y
apt -y install libpcre3-dev libssl-dev unzip build-essential daemon libxml2-dev libxslt1-dev libgd-dev libgeoip-dev zlib1g-dev libpcre3

Installieren Sie die MindMax-Datenbank, damit Sie GEO-IP-Regeln basierend auf dem Standort ausführen können. Mit dieser Datenbank können Sie den Verkehr basierend auf dem Standort routen oder blockieren. Unsere NGINX-Protokolle zeigen nun das Land des Benutzers an, selbst wenn Sie die Geo-Blockierung nicht aktivieren.

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

NGINX und NAXSI WAF herunterladen und extrahieren

Hinweis: Ersetzen Sie NGINX durch die neueste Version

mkdir ~/nginx-waf
wget https://nginx.org/download/nginx-1.16.1.tar.gz -O ~/nginx-waf/nginx.tar.gz
tar xzf ~/nginx-waf/nginx.tar.gz -C ~/nginx-waf
wget https://github.com/nbs-system/naxsi/archive/master.zip -O ~/nginx-waf/waf.zip
unzip ~/nginx-waf/waf.zip -d ~/nginx-waf/

Git-Clone des GEO IP2-Moduls für NGINX

apt install -y git
git clone https://github.com/leev/ngx_http_geoip2_module.git /etc/ngx_http_geoip2_module

NGINX kompilieren

Wir erstellen ein Skript, das dies für uns erledigt, und führen es unten aus.


cat > ~/nginx-waf/nginx-1.16.1/install.sh <<\EOF
cd ~/nginx-waf/nginx-1.16.1/
./configure --conf-path=/etc/nginx/nginx.conf --add-module=../naxsi-master/naxsi_src/ --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --user=www-data --group=www-data --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --without-http_uwsgi_module --add-dynamic-module=/etc/ngx_http_geoip2_module --without-http_scgi_module --prefix=/usr
make
make install
EOF

sh ~/nginx-waf/nginx-1.16.1/install.sh

Firewall-Regeln erstellen

Die unten stehende Standardkonfiguration aktiviert die WAF und blockiert bösartige Anfragen. Wenn Sie die WAF im Lernmodus ausführen möchten, können Sie dies tun, indem Sie „Learning Mode“ zur Regeldatei unten hinzufügen.

cp ~/nginx-waf/naxsi-master/naxsi_config/naxsi_core.rules /etc/nginx/



cat > /etc/nginx/naxsi.rules <<\EOF
SecRulesEnabled;
DeniedUrl "/RequestDenied";
## Prüfen Sie Naxsi-Regeln
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
EOF

NGINX-Konfigurationsdatei erstellen

Standardmäßig ist in dieser Konfigurationsdatei die Geo-Blockierung auskommentiert, Sie können sie jedoch auskommentieren und aktivieren, wenn Sie möchten.

Hinweis: Wir müssen NGINX zunächst OHNE SSL ausführen, da wir benötigen, dass certbot eine live Domain sieht. Wir werden in einem späteren Schritt SSL erhalten und tatsächlich eine neue NGINX-Conf-Datei herunterladen, um diese zu ersetzen.

Hinweis: Ersetzen Sie cloudforums.net durch Ihren Domainnamen.

cat > /etc/nginx/nginx.conf <<\EOF
#user  nobody;
worker_processes  1;
load_module modules/ngx_http_geoip2_module.so;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    include       /etc/nginx/naxsi_core.rules;
        include     /etc/nginx/conf.d/*.conf;
        include     /etc/nginx/sites-enabled/*;
    
    geoip2 /etc/geo_ip/GeoLite2-Country.mmdb {
        $geoip2_data_country_code source=$remote_addr country iso_code;
        $geoip2_data_country_name source=$remote_addr country names en;
    }  
    log_format  main_geo  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" '
                          '$geoip2_data_country_code $geoip2_data_country_name';
    
    access_log /var/log/nginx/access.log main_geo;
   
    default_type  application/octet-stream;
    error_log /var/log/nginx/error.log;
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name cloudforums.net;
        root /;
 
        location /.well-known/acme-challenge/ {
                root /var/www;
        }
        location / {
            return 301 https://$host$request_uri;
            include /etc/nginx/naxsi.rules;
                root   html;
                index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
EOF

Upstart-Skript für NGINX erstellen

Wir müssen ein Skript für den NGINX-Dienst erstellen, damit er gestartet werden kann.

cat > /etc/init.d/nginx <<\EOF
#! /bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 
 DAEMON=/usr/sbin/nginx 
 NAME=nginx 
 DESC=nginx
 
 test -x $DAEMON || exit 0 
 # Fügen Sie NGINX-Standardwerte hinzu, falls verfügbar 
 if [ -f /etc/nginx ] ; then 
         . /etc/nginx 
 fi
 
 set -e
 
 case "$1" in 
     start)
         echo -n „Starten von $DESC: " 
         start-stop-daemon --start --quiet --pidfile /var/run/nginx.pid \ 
             --exec $DAEMON -- $DAEMON_OPTS 
         echo „$NAME." 
         ;; 
     stop) 
         echo -n „Stoppen von $DESC: " 
         start-stop-daemon --stop --quiet --pidfile /var/run/nginx.pid \ 
             --exec $DAEMON 
         echo „$NAME." 
         ;; 
     restart|force-reload) 
         echo -n „Neustarten von $DESC: " 
         start-stop-daemon --stop --quiet --pidfile \ 
             /var/run/nginx.pid --exec $DAEMON 
         sleep 1 start-stop-daemon --start --quiet --pidfile \ 
             /var/run/nginx.pid --exec $DAEMON -- $DAEMON_OPTS 
         echo „$NAME." 
         ;; 
     reload) 
         echo -n „Neuladen der $DESC-Konfiguration: " 
         start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/nginx.pid \ 
             --exec $DAEMON 
         echo „$NAME." 
         ;; 
     *) 
         N=/etc/init.d/$NAME 
         echo „Verwendung: $N {start|stop|restart|force-reload}" >&2 
         exit 1 
         ;; 
 esac
 
 exit 0
EOF

systemctl daemon-reload

NGINX-Dienstdatei erstellen

cat > /lib/systemd/system/nginx.service <<\EOF
[Unit]
Description=Ein leistungsstarker Webserver und ein Reverse-Proxy-Server
Documentation=man:nginx(8)
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF

Geo IP-Länderdatenbank herunterladen

mkdir /etc/geo_ip
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
gzip -d GeoLite2-Country.mmdb.gz
mv GeoLite2-Country.mmdb /etc/geo_ip/

NGINX aktivieren und starten

systemctl stop apache2
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx

SSL-Zertifikat für Ihre Domain hinzufügen

Vergessen Sie nicht, cloudforums.net durch Ihre domain.com zu ersetzen.

mkdir /var/www
apt-get -y update
apt-get -y install letsencrypt
yes „n" | letsencrypt certonly --webroot --agree-tos -w /var/www -d cloudforums.net -m youremail@domain.com

Neue NGINX-Datei mit SSL-Regeln erstellen

Erstellen Sie eine neue NGINX-Datei mit dem SSL-Zertifikat, das Sie gerade heruntergeladen haben.

Hinweis: Ändern Sie cloudforums.net in Ihre Domain.


cat > /etc/nginx/nginx.conf <<\EOF
#user  nobody;
worker_processes  1;
load_module modules/ngx_http_geoip2_module.so;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    include       /etc/nginx/naxsi_core.rules;
        include     /etc/nginx/conf.d/*.conf;
        include     /etc/nginx/sites-enabled/*;
    
    geoip2 /etc/geo_ip/GeoLite2-Country.mmdb {
        $geoip2_data_country_code source=$remote_addr country iso_code;
        $geoip2_data_country_name source=$remote_addr country names en;
    }  
    log_format  main_geo  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" '
                          '$geoip2_data_country_code $geoip2_data_country_name';
    
    #***********************************************************
    #Auskommentieren, um Geo-Blocking durchzuführen. Standardmäßig ist in den untenstehenden Einstellungen nur die USA aktiviert
    #***********************************************************
    #map $geoip2_data_country_code $allowed_country {
    #    default no;
    #    US yes;
    # }
    access_log /var/log/nginx/access.log main_geo;
   
    default_type  application/octet-stream;
    error_log /var/log/nginx/error.log;
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name  cloudforums.net;
        root /;
 
        location /.well-known/acme-challenge/ {
                root /var/www;
        }
        location / {
            return 301 https://$server_name$request_uri;
            include /etc/nginx/naxsi.rules;
                root   html;
                index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
      listen 443 ssl;  listen [::]:443 ssl;
      server_name cloudforums.net;  
      ssl on;
      ssl_certificate      /etc/letsencrypt/live/cloudforums.net/fullchain.pem;
      ssl_certificate_key  /etc/letsencrypt/live/cloudforums.net/privkey.pem;
      ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
      ssl_protocols TLSv1.2;
      ssl_prefer_server_ciphers on;
      ssl_session_cache shared:SSL:10m;
      add_header Strict-Transport-Security „max-age=63072000;";
      ssl_stapling on;
      ssl_stapling_verify on;
      client_max_body_size 0;
      location / {
        proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
       }
    }
    # HTTPS-Server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;
    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}
EOF

NGINX neu starten

systemctl restart nginx

Sie haben jetzt eine großartige Open-Source-WAF!! :slight_smile:

Schamlose Werbung

Vergessen Sie nicht, uns bei cloudforums.net beizutreten, wenn Ihnen dieser Leitfaden gefallen hat. Wir würden uns sehr freuen, Sie hier zu haben. Wir verkaufen nichts und haben keine Werbung. Wir suchen nur nach guten IT-Beiträgen :slight_smile:

Automatisierte Ein-Klick-Installation von NGINX / WAF nach der Discourse-Installation. Vergessen Sie nicht, den Domainnamen von cloudforums.net in Ihre eigene Domain zu ändern.

Führen Sie einfach aus

sh discourse_install.sh