diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/consumer-for b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/consumer-for new file mode 100644 index 000000000..09a147a5f --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/consumer-for @@ -0,0 +1 @@ +certsync diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/dependencies.d/log-prepare b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/dependencies.d/log-prepare new file mode 100644 index 000000000..e69de29bb diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/pipeline-name b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/pipeline-name new file mode 100644 index 000000000..204da2771 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/pipeline-name @@ -0,0 +1 @@ +certsync-pipeline diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/run new file mode 100755 index 000000000..7d66e2c81 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/run @@ -0,0 +1,4 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +exec logutil-service /dev/shm/logs/certsync diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/type b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/type new file mode 100644 index 000000000..5883cff0c --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync-log/type @@ -0,0 +1 @@ +longrun diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/dependencies.d/nginx b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/dependencies.d/nginx new file mode 100644 index 000000000..e69de29bb diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/finish b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/finish new file mode 100755 index 000000000..3450034b2 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/finish @@ -0,0 +1,30 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +# Take down the S6 supervision tree when the service fails + +set -o errexit -o nounset -o pipefail + +# Logs should be sent to stdout so that s6 can collect them + +declare exit_code_container +exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) +readonly exit_code_container +readonly exit_code_service="${1}" +readonly exit_code_signal="${2}" +readonly service="CERTSYNC" + +echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" + +if [[ "${exit_code_service}" -eq 256 ]]; then + if [[ "${exit_code_container}" -eq 0 ]]; then + echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode + fi + if [[ "${exit_code_signal}" -eq 15 ]]; then + exec /run/s6/basedir/bin/halt + fi +elif [[ "${exit_code_service}" -ne 0 ]]; then + if [[ "${exit_code_container}" -eq 0 ]]; then + echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode + fi + exec /run/s6/basedir/bin/halt +fi diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/producer-for b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/producer-for new file mode 100644 index 000000000..886683fd9 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/producer-for @@ -0,0 +1 @@ +certsync-log diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run new file mode 100755 index 000000000..5e53fd310 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run @@ -0,0 +1,59 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +# Start the CERTSYNC service + +set -o errexit -o nounset -o pipefail + +# Logs should be sent to stdout so that s6 can collect them + +echo "[INFO] Starting certsync..." + +lefile="/etc/letsencrypt/live/frigate/fullchain.pem" + +if [ ! -e $lefile ] +then + echo "[ERROR] TLS certificate does not exist: $lefile" + exit 1 +fi + + +while true +do + + leprint=`openssl x509 -in $lefile -fingerprint -noout` + + case "$leprint" in + *Fingerprint*) + ;; + *) + echo "[ERROR] Missing fingerprint from $lefile" + # exit 1 + ;; + esac + + # i think this should work without '-servername "$domain"' + liveprint=`echo | openssl s_client -showcerts -connect 127.0.0.1:443 2>&1 | openssl x509 -fingerprint | grep -i fingerprint` + + case "$liveprint" in + *Fingerprint*) + ;; + *) + echo "[ERROR] Missing fingerprint from current TLS cert" + # exit 1 + ;; + esac + + if [ "$leprint" != "$liveprint" ] + then + echo "[INFO] Reloading nginx to refresh TLS certificate" + echo "$lefile: $leprint" + /usr/local/nginx/sbin/nginx -s reload + fi + + # certbot certonly --cert-name frigate --webroot -w /etc/letsencrypt/www --keep-until-expiring --deploy-hook "/usr/local/nginx/sbin/nginx -s reload" + + sleep 60 + +done + +exit 0 \ No newline at end of file diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/timeout-kill b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/timeout-kill new file mode 100644 index 000000000..3a05c8b3e --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/timeout-kill @@ -0,0 +1 @@ +30000 diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/type b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/type new file mode 100644 index 000000000..5883cff0c --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/type @@ -0,0 +1 @@ +longrun diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/log-prepare/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/log-prepare/run index 0d8d73ce2..c493e320e 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/log-prepare/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/log-prepare/run @@ -4,7 +4,7 @@ set -o errexit -o nounset -o pipefail -dirs=(/dev/shm/logs/frigate /dev/shm/logs/go2rtc /dev/shm/logs/nginx) +dirs=(/dev/shm/logs/frigate /dev/shm/logs/go2rtc /dev/shm/logs/nginx /dev/shm/logs/certsync) mkdir -p "${dirs[@]}" chown nobody:nogroup "${dirs[@]}" diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check new file mode 100755 index 000000000..8307a7956 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e + +# Wait for PID file to exist. +while ! test -f /run/nginx.pid; do sleep 1; done \ No newline at end of file diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index c6292937d..82ea1249b 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -22,6 +22,21 @@ function set_worker_processes() { set_worker_processes +mkdir -p /etc/letsencrypt/www + +# Create self signed certs if needed +letsencrypt_path=/etc/letsencrypt/live/frigate +mkdir -p $letsencrypt_path + +if [ ! \( -f "$letsencrypt_path/privkey.pem" -a -f "$letsencrypt_path/fullchain.pem" \) ]; then + echo "[INFO] No TLS certificate found. Generating a self signed certificate..." + openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ + -subj "/O=FRIGATE DEFAULT CERT/CN=*" \ + -keyout "$letsencrypt_path/privkey.pem" -out "$letsencrypt_path/fullchain.pem" +fi + # Replace the bash process with the NGINX process, redirecting stderr to stdout exec 2>&1 -exec nginx +exec \ + s6-notifyoncheck -t 30000 -n 1 \ + nginx diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/certsync-pipeline b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/certsync-pipeline new file mode 100644 index 000000000..e69de29bb diff --git a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf index 546040fc5..a996145f2 100644 --- a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf +++ b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf @@ -56,9 +56,12 @@ http { keepalive 1024; } - upstream go2rtc { - server 127.0.0.1:1984; - keepalive 1024; + server { + listen [::]:80 ipv6only=off default_server; + + location / { + return 301 https://$host$request_uri; + } } server { @@ -67,6 +70,8 @@ http { # intended for internal traffic, not protected by auth listen [::]:5000 ipv6only=off; + include tls.conf; + # vod settings vod_base_url ''; vod_segments_base_url ''; diff --git a/docker/main/rootfs/usr/local/nginx/conf/tls.conf b/docker/main/rootfs/usr/local/nginx/conf/tls.conf new file mode 100644 index 000000000..9180caf00 --- /dev/null +++ b/docker/main/rootfs/usr/local/nginx/conf/tls.conf @@ -0,0 +1,18 @@ +keepalive_timeout 70; +listen [::]:443 ipv6only=off default_server ssl; + +ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem; + +# generated 2024-06-01, Mozilla Guideline v5.7, nginx 1.25.3, OpenSSL 1.1.1w, modern configuration, no OCSP +# https://ssl-config.mozilla.org/#server=nginx&version=1.25.3&config=modern&openssl=1.1.1w&ocsp=false&guideline=5.7 +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; # about 40000 sessions +ssl_session_tickets off; + +# modern configuration +ssl_protocols TLSv1.3; +ssl_prefer_server_ciphers off; + +# HSTS (ngx_http_headers_module is required) (63072000 seconds) +add_header Strict-Transport-Security "max-age=63072000" always; \ No newline at end of file