Reverse-Proxy Jail

Das erstellen der Jail ist gleich zu dem wie in der Webserver Jail.

Natürlich aber mit anderen IP-Adressen (/etc/hosts der Jail):

::1                     localhost
127.0.0.1               localhost

fd10:23:42:23::5        reverse.example.com
10.23.42.5              reverse.example.com

Hier ist eine IPv4 Adresse leider zwingend nötig, es gibt nach wie vor Leute, die dieses steinalte Protokoll nutzen…

NGINX

Innerhalb der Jail bauen wir uns nginx:

$ cd /usr/ports/www/nginx
$ make config-recursive install

Die Standardeinstellungen sind fein.

Danach wird in der /etc/rc.conf der Webserver aktiviert:

nginx_enable="YES"

Auch hier habe ich mir einen eigenen Satz an Konfigurationsdateien gebastelt:

$ find /usr/local/etc/nginx/ -type f
/usr/local/etc/nginx/mime.types
/usr/local/etc/nginx/nginx.conf
/usr/local/etc/nginx/conf/general.conf
/usr/local/etc/nginx/conf/proxy.conf
/usr/local/etc/nginx/conf/letsencrypt.conf
/usr/local/etc/nginx/sites/_sinkhole.conf
/usr/local/etc/nginx/sites/demo.example.com.conf
/usr/local/etc/nginx/sites/www.example.com.conf
  • /usr/local/etc/nginx/mime.types stammt aus der Standardkonfiguration.
  • /usr/local/etc/nginx/nginx.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
user www;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    multi_accept on;
    worker_connections 65535;
}

http {
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 2048;
    client_max_body_size 64M;

    # MIME
    include mime.types;
    default_type application/octet-stream;

    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # SSL
    ssl_session_timeout 10m;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites
    ssl_dhparam /usr/local/etc/nginx/dhparam.pem;

    # intermediate configuration
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_ecdh_curve secp384r1;
    ssl_prefer_server_ciphers on;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 208.67.222.222 208.67.220.220 valid=300s;
    resolver_timeout 5s;

    # Security Headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    # load configs
    include sites/*.conf;
}
  • /usr/local/etc/nginx/conf/general.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;

# dot files
location ~ /\. {
    deny all;
}

# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
  • /usr/local/etc/nginx/conf/proxy.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_cache_bypass $http_upgrade;
  • /usr/local/etc/nginx/conf/letsencrypt.conf
1
2
3
4
# ACME-challenge
location ^~ /.well-known/acme-challenge/ {
    root /usr/local/www/_letsencrypt;
}
  • /usr/local/etc/nginx/sites/_sinkhole.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
    listen 10.23.42.2:443 ssl http2;
    listen [fd10:23:42:23::2]:443 ssl http2;

    server_name _;

    # SSL
    ssl_certificate /usr/local/etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

    return 444;
}

# HTTP redirect
server {
    listen 10.23.42.2:80;
    listen [fd10:23:42:23::2]:80;

    server_name _;

    return 444;
}
  • /usr/local/etc/nginx/sites/demo.example.com
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
    listen 10.23.42.2:443 ssl http2;
    listen [fd10:23:42:23::2]:443 ssl http2;

    server_name demo.example.com;

    # SSL
    ssl_certificate /usr/local/etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

    # logging
    access_log /var/log/nginx/demo.example.com.access.log;
    error_log /var/log/nginx/demo.example.com.error.log warn;

    # reverse proxy
    location / {
        proxy_pass http://[fd10:23:42:23::5]:80;
        include conf/proxy.conf;
    }

    include conf/general.conf;
}

# HTTP redirect
server {
    listen 10.23.42.2:80;
    listen [fd10:23:42:23::2]:80;

    server_name demo.example.com;

    include conf/letsencrypt.conf;

    location / {
        return 301 https://demo.example.com$request_uri;
    }
}

  • /usr/local/etc/nginx/sites/www.example.com
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
    listen 10.23.42.2:443 ssl http2;
    listen [fd10:23:42:23::2]:443 ssl http2;

    server_name www.example.com;

    # SSL
    ssl_certificate /usr/local/etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

    # logging
    access_log /var/log/nginx/www.example.com.access.log;
    error_log /var/log/nginx/www.example.com.error.log warn;

    # reverse proxy
    location / {
        proxy_pass http://[fd10:23:42:23::3]:80;
        include conf/proxy.conf;
    }

    include conf/general.conf;
}

# HTTP redirect
server {
    listen 10.23.42.2:80;
    listen [fd10:23:42:23::2]:80;

    server_name www.example.com;

    include conf/letsencrypt.conf;

    location / {
        return 301 https://www.example.com$request_uri;
    }
}

Let’s Encrypt

Als erstes benötigen wir den certbot:

$ cd /usr/ports/security/py-certbot
$ make config-recursive install

Dann basteln wir uns Diffie-Hellman Keys:

$ openssl dhparam -dsaparam -out /usr/local/etc/nginx/dhparam.pem 4096

Wir brauchen einen Ordner für die ACME-challenge:

$ mkdir /usr/local/www/_letsencrypt
$ chown www:www /usr/local/www/_letsencrypt

Jetzt basteln wir uns ein Zertifikat:

certbot certonly --webroot \
    -d example.com -d www.example.com -d demo.example.com \
    --email letsencrypt@example.com \
    --webroot-path /usr/local/www/_letsencrypt \
    --non-interactive \
    --agree-tos \
    --force-renewal