DK1MI.de

Hosting von Gitea und FreshRSS unter OpenBSD mit httpd und relayd

Read this article in English language

Dieser Artikel versucht, die wichtigsten Schritte zu dokumentieren, um folgendes mit einem zuvor frisch installierten OpenBSD 7.4 zu erreichen:

Das Ziel ist es, eingebaute Dienste wie httpd, relayd und acme anstelle von Drittanbieterpaketen zu verwenden. Du wirst hier keine Installation/Konfiguration von Datenbanksystemen finden, da ich SQLite sowohl für Gitea als auch für FreshRSS verwende. Der Schwerpunkt liegt auf den Serverkomponenten, nicht auf den gehosteten Anwendungen, daher werde ich nicht näher darauf eingehen, wie diese zu konfigurieren sind.

Paketfilter: pf und sshguard

Installiere sshguard:

$ pkg_add sshguard

Bearbeite /etc/pf.conf, füge das Folgende ein und passe es an deine Bedürfnisse an:

table <martians> {
  0.0.0.0/8 10.0.0.0/8 100.64.0.0/10            \
  127.0.0.0/8 169.254.0.0/16 172.16.0.0/12      \
  192.0.0.0/24 192.0.2.0/24 192.88.99.0/24      \
  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24  \
  203.0.113.0/24 224.0.0.0/3 255.255.255.255/32 \
  ::/128 ::/96 ::1/128 ::ffff:0:0/96 100::/64   \
  2001:10::/28 2001:2::/48 2001:db8::/32        \
  3ffe::/16 fec0::/10 fc00::/7 }
 
## Set http(80)/https (443) port here ##
webports = "{http, https}"
 
## enable these services ##
int_tcp_services = "{domain, ntp, smtp, www, https, ftp, ssh, 31415}"
int_udp_services = "{domain, ntp}"

set block-policy drop
set loginterface egress
 
## Skip loop back interface - Skip all PF processing on interface ##
set skip on lo

match in all scrub (no-df random-id max-mss 1440)
match out on egress inet from !(egress:network) to any nat-to (egress:0)
 
## Blocking spoofed packets
antispoof quick for egress

# Drop all Non-Routable Addresses 
block in quick on egress from <martians> to any
block return out quick on egress from any to <martians>
 
## Set default policy ##
block all

table <sshguard> persist
block in quick proto tcp from <sshguard>
 
pass out quick
 
# Allow SSH
pass in inet proto tcp to egress port ssh
pass in inet6 proto tcp to egress port ssh

# Allow ICMP
pass in on egress inet proto icmp all icmp-type echoreq
pass in on egress inet6 proto icmp6 all icmp6-type echoreq

# Allow access to httpd and relayd
pass in inet proto { tcp udp } to egress port $webports
pass in inet6 proto { tcp udp } to egress port $webports
 
# Allow essential outgoing traffic 
pass out quick proto tcp to any port $int_tcp_services
pass out quick proto udp to any port $int_udp_services
pass out quick inet6 proto tcp to any port $int_tcp_services
pass out quick inet6 proto udp to any port $int_udp_services

Öffne eine screen-Session und führe die folgenden Schritte aus:

$ sleep 120; pfctl -d

So können wir die Pf-Konfiguration neu laden, ohne uns dauerhaft auszusperren. Wenn wir einen Fehler machen, wird pf spätestens nach 2 Minuten deaktiviert, sodass wir uns wieder per SSH einloggen und den Fehler beheben können.

$ pfctl -n -f /etc/pf.conf
$ pfctl -f /etc/pf.conf

Versuche, dich nach dem Neuladen der Konfiguration per SSH einzuloggen, um sicherzustellen, dass zumindest dies noch funktioniert. Wenn alles in Ordnung ist, vergiss nicht, den Prozess "sleep 120; pfctl -d" zu beenden.

Webserver: httpd und PHP

In diesem Schritt werden wir httpd so konfigurieren, dass er statische HTML- und PHP-Dateien ausliefert. Außerdem wird er für den Abruf von SSL-Zertifikaten von Let's Encrypt über den ACME-Client benötigt.

Bearbeite /etc/httpd, füge das Folgende ein und passe es an deine Bedürfnisse an:

server "static.dk1mi.radio" {
   listen on * port 80
   root "/htdocs/static.dk1mi.radio"
   log style combined

   location "/.well-known/acme-challenge/*" {
      root "/acme"
      request strip 2
    }
}

server "blogs.radio" {
   listen on * port 80
   location "/*.php*" { fastcgi socket "/run/php-fpm.sock" }
   root "/freshrss/p/"
   directory index index.php
   log style combined

   location "/.well-known/acme-challenge/*" {
      root "/acme"
      request strip 2
   }
}

server "git.dk1mi.radio" {
   listen on * port 80
   log style combined

   location "/.well-known/acme-challenge/*" {
      root "/acme"
      request strip 2
   }

   location * {
       block return 301 "https://$HTTP_HOST$REQUEST_URI"
   }
}

Enable und starte PHP:

$ rcctl enable php81_fpm
$ rcctl start php81_fpm

Enable und starte httpd:

$ rcctl enable httpd
$ rcctl start httpd

Jetzt ist es an der Zeit, ACME so zu konfigurieren, dass es unsere SSL-Zertifikate abruft:

Bearbeite /etc/acme-client.conf, füge das Folgende ein und passe es an deine Bedürfnisse an:

authority letsencrypt {
        api url "https://acme-v02.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-privkey.pem"
}

authority letsencrypt-staging {
        api url "https://acme-staging.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-staging-privkey.pem"
}

domain blogs.radio {
       domain key "/etc/ssl/private/blogs.radio.key"
       domain full chain certificate "/etc/ssl/blogs.radio.crt"
       sign with letsencrypt
}

domain git.dk1mi.radio {
       domain key "/etc/ssl/private/git.dk1mi.radio.key"
       domain full chain certificate "/etc/ssl/git.dk1mi.radio.crt"
       sign with letsencrypt
}

domain static.dk1mi.radio {
       domain key "/etc/ssl/private/static.dk1mi.radio.key"
       domain full chain certificate "/etc/ssl/static.dk1mi.radio.crt"
       sign with letsencrypt
}

Wir können jetzt unsere neuen Zertifikate erstellen und abrufen:

$ /usr/sbin/acme-client -v blogs.radio
$ /usr/sbin/acme-client -v git.dk1mi.radio
$ /usr/sbin/acme-client -v static.dk1mi.radio

Um sicherzustellen, dass sie regelmäßig aktualisiert werden, fügen wir die folgenden Zeilen in unsere crontab ein:

$ crontab -e
0 2 * * * /usr/sbin/acme-client -v beta.blogs.radio >> /tmp/acme.log 2>&1
5 2 * * * /usr/sbin/acme-client -v git.dk1mi.radio >> /tmp/acme.log 2>&1
10 2 * * * /usr/sbin/acme-client -v static.dk1mi.radio >> /tmp/acme.log 2>&1

Nachdem dies geschehen ist, können wir relayd konfigurieren und starten.

Relay Daemon: relayd

Wir werden relayd nutzen, um SSL-Verbindungen zu beenden und HTTP-Anfragen intern entweder an httpd oder den gitea-Daemon weiterzuleiten.

Bearbeite dazu /etc/relayd, füge das Folgende ein und passe es an deine Bedürfnisse an:

# Macros -----------------------------------
ext_ipv4="46.23.93.217"
ext_ipv6="2a03:6000:93f4:614::217"
webhost="127.0.0.1"
webhost6="::1"

table <webserver>  { $webhost }
table <gitea> { $webhost }
table <webserver6> { $webhost6 }

http protocol https {
  tls keypair git.dk1mi.radio
  tls keypair static.dk1mi.radio
  tls keypair blogs.radio

  block
  pass request header "Host" value "git.dk1mi.radio" \
    forward to <gitea>
  pass request header "Host" value "static.dk1mi.radio" \
    forward to <webserver>
  pass request header "Host" value "blogs.radio" \
    forward to <webserver>
}

relay https {
  listen on $ext_ipv4 port 443 tls
  protocol https
  forward to <webserver> port 80 mode roundrobin \
    check http "/" code 200
  forward to <gitea> port 3000
}

relay https6 {
  listen on $ext_ipv6 port 443 tls
  protocol https
  forward to <webserver6> port 80 mode roundrobin \
    check http "/" code 200
  forward to <gitea> port 3000
}

Enable und starte relayd:

$ rcctl enable relayd
$ rcctl start relayd

FreshRSS

Installiere FreshRSS und einige Abhängigkeiten:

$ pkg_add freshrss php-zip php-curl

FreshRSS sollte jetzt über deinen Browser erreichbar und konfigurierbar sein.

Füge die folgende Zeile in deine crontab ein, um alle RSS-Feeds automatisch alle 5 Minuten zu aktualisieren:

*/5 * * * * doas -u www /usr/local/bin/php -f /var/www/freshrss/app/actualize_script.php > /tmp/FreshRSS.log 2>&1

Gitea

$ pkg_add gitea

Enable und starte gitea sowie gitdaemon:

$ rcctl enable gitea gitdaemon 
$ rcctl enable gitea gitdaemon 
$ rcctl start gitdaemon
$ rcctl start gitdaemon

Gitea sollte jetzt über deinen Browser erreichbar und konfigurierbar sein.