From 322704c6bcea422e7c585939205c2b3f2470e8e0 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 13 May 2026 17:20:23 +1000 Subject: [PATCH 01/12] Update Webmin conf script to also write IPv6 rules --- conf/turnkey.d/webmin-fw | 66 ++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/conf/turnkey.d/webmin-fw b/conf/turnkey.d/webmin-fw index e1619a6b..1faccf41 100755 --- a/conf/turnkey.d/webmin-fw +++ b/conf/turnkey.d/webmin-fw @@ -1,10 +1,23 @@ -#!/bin/sh -e +#!/bin/bash -e -set ${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321} +# TODO: drop use of iptables-legacy and use nftables directly -CONF=/etc/iptables.up.rules +set "${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321}" +# Read into an array of sorted unique values +readarray -t WEBMIN_FW_TCP_INCOMING \ + < <(tr ' ' '\n' <<< "$WEBMIN_FW_TCP_INCOMING" | sort -un) -cat > $CONF < "$conf" <> $CONF -done - -if [ "$WEBMIN_FW_UDP_INCOMING" ]; then - for port in $WEBMIN_FW_UDP_INCOMING; do - echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> $CONF + for port in "${WEBMIN_FW_TCP_INCOMING[@]}"; do + echo "-A INPUT -p tcp -m tcp --dport $port -j ACCEPT" >> "$conf" done -fi -if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then - for port in $WEBMIN_FW_TCP_INCOMING_REJECT; do - echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> $CONF - done -fi + if [[ "$WEBMIN_FW_UDP_INCOMING" ]]; then + readarray -t WEBMIN_FW_UDP_INCOMING \ + < <(tr ' ' '\n' <<< "$WEBMIN_FW_UDP_INCOMING" | sort -un) + for port in "${WEBMIN_FW_UDP_INCOMING[@]}"; do + echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> "$conf" + done + fi -echo "COMMIT" >> $CONF + if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then + readarray -t WEBMIN_FW_TCP_INCOMING_REJECT \ + < <(tr ' ' '\n' <<< "$WEBMIN_FW_TCP_INCOMING_REJECT" | sort -un) + for port in "${WEBMIN_FW_TCP_INCOMING_REJECT[@]}"; do + echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> "$conf" + done + fi -sed -i "/^$/d" $CONF + echo "COMMIT" >> "$conf" + sed -i "/^$/d" "$conf" +done -# As of Buster, Debian uses nftables for firewall; but webmin only supports legacy -# iptables - see https://github.com/webmin/webmin/issues/1097 +# Debian has been using nftables for firewall for some time; but historically +# Webmin only supported legacy iptables. Webmin now supports nftables so as per +# TODO at top of this file TKL should migrate to nftables, but for now we'll +# continue to leverage legacy iptables functionality via 'iptables-legacy'. +# +# See https://github.com/webmin/webmin/issues/1097 update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy From 2fe4e0148ffd0ad5288ced470dc1b31b25c66724 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Thu, 14 May 2026 12:34:22 +1000 Subject: [PATCH 02/12] Enable HSTS, redirect HTTP => HTTPS and note disabling TLSv1.2 in future --- conf/turnkey.d/webmin-conf | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/conf/turnkey.d/webmin-conf b/conf/turnkey.d/webmin-conf index 97b63661..7cad92b2 100755 --- a/conf/turnkey.d/webmin-conf +++ b/conf/turnkey.d/webmin-conf @@ -5,10 +5,10 @@ CONF=/etc/webmin/miniserv.conf update_or_add() { key=$1 value=$2 - if grep -q "$key" $CONF; then - sed -i "s|$key=.*|$key=$value|" $CONF + if grep -q "$key" "$CONF"; then + sed -i "s|$key=.*|$key=$value|" "$CONF" else - echo "$key=$value" >> $CONF + echo "$key=$value" >> "$CONF" fi } @@ -23,6 +23,8 @@ update_or_add error_handler_403 403.cgi update_or_add nolog '\/stats\.cgi\?xhr\-stats\=general' update_or_add no_tls1 1 update_or_add no_tls1_1 1 +# TODO: Disable TLSv1.2 in a future release (i.e. append '1': 'no_tls1_2 1') update_or_add no_tls1_2 update_or_add extracas -update_or_add ssl_hsts 0 +update_or_add ssl_hsts 1 +update_or_add ssl_redirect 1 From 492ed75ac2437a3a3730e59cf7a6fbc0f07193e7 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 15 May 2026 11:50:24 +1000 Subject: [PATCH 03/12] Update logging and merge into conf/turnkey.d/webmin-conf; rename webmin-conf-logging --- .../{webmin-conf => webmin-conf-logging} | 19 +++++++++++++++++++ conf/turnkey.d/webmin-handy-log | 13 ------------- 2 files changed, 19 insertions(+), 13 deletions(-) rename conf/turnkey.d/{webmin-conf => webmin-conf-logging} (52%) delete mode 100755 conf/turnkey.d/webmin-handy-log diff --git a/conf/turnkey.d/webmin-conf b/conf/turnkey.d/webmin-conf-logging similarity index 52% rename from conf/turnkey.d/webmin-conf rename to conf/turnkey.d/webmin-conf-logging index 7cad92b2..85278831 100755 --- a/conf/turnkey.d/webmin-conf +++ b/conf/turnkey.d/webmin-conf-logging @@ -1,6 +1,7 @@ #!/bin/sh -e CONF=/etc/webmin/miniserv.conf +LOG_DIR=/var/log/webmin update_or_add() { key=$1 @@ -28,3 +29,21 @@ update_or_add no_tls1_2 update_or_add extracas update_or_add ssl_hsts 1 update_or_add ssl_redirect 1 +# update logfile location +update_or_add logfile "$LOG_DIR/miniserv.log" +update_or_add errorlog "$LOG_DIR/miniserv.error" + +# Note: Updating Webmin config for it's own log file as below does not actually +# work (continues to log to /var/webmin/webmin.log) but we'll work around that +# via symlinks and update the config file to point to the actual log file +# anyway. +CONF=/etc/webmin/config +update_or_add logfile "$LOG_DIR/webmin.log" + +# Prime log files and set permissions +mkdir -p "$LOG_DIR" +touch "$LOG_DIR{miniserv.log,miniserv.error,webmin.log}" +chmod 750 "$LOG_DIR" +chmod 640 "$LOG_DIR"*.log +rm -f /var/webmin/webmin.log +ln -sf /var/log/webmin/webmin.log /var/webmin/webmin.log diff --git a/conf/turnkey.d/webmin-handy-log b/conf/turnkey.d/webmin-handy-log deleted file mode 100755 index 20354494..00000000 --- a/conf/turnkey.d/webmin-handy-log +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -# set up convenience links to Webmin log files - -WEBMIN_VAR=/var/webmin -WEBMIN_LOG=/var/log/webmin - -mkdir -p $WEBMIN_LOG - -files=(miniserv.error webmin.log) -for f in "${files[@]}"; do - ln -s "$WEBMIN_VAR/$f" "$WEBMIN_LOG/$f" -done From 4d2690cc967651874f3adeb78bb115ffc4910ae1 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 19 May 2026 14:34:10 +1000 Subject: [PATCH 04/12] Bugfix webmin-conf-logging --- conf/turnkey.d/webmin-conf-logging | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/turnkey.d/webmin-conf-logging b/conf/turnkey.d/webmin-conf-logging index 85278831..c73fd286 100755 --- a/conf/turnkey.d/webmin-conf-logging +++ b/conf/turnkey.d/webmin-conf-logging @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e CONF=/etc/webmin/miniserv.conf LOG_DIR=/var/log/webmin @@ -42,8 +42,8 @@ update_or_add logfile "$LOG_DIR/webmin.log" # Prime log files and set permissions mkdir -p "$LOG_DIR" -touch "$LOG_DIR{miniserv.log,miniserv.error,webmin.log}" +touch "$LOG_DIR"/{miniserv.log,miniserv.error,webmin.log} chmod 750 "$LOG_DIR" -chmod 640 "$LOG_DIR"*.log +chmod 640 "$LOG_DIR"/*.log rm -f /var/webmin/webmin.log ln -sf /var/log/webmin/webmin.log /var/webmin/webmin.log From b654e3e421309a44d580b42f7984e9a65257ab92 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 19 May 2026 14:46:23 +1000 Subject: [PATCH 05/12] Work around bash script race condition (process substitution directly into readarray) --- conf/turnkey.d/webmin-fw | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/conf/turnkey.d/webmin-fw b/conf/turnkey.d/webmin-fw index 1faccf41..3e01d5e6 100755 --- a/conf/turnkey.d/webmin-fw +++ b/conf/turnkey.d/webmin-fw @@ -3,9 +3,19 @@ # TODO: drop use of iptables-legacy and use nftables directly set "${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321}" + # Read into an array of sorted unique values -readarray -t WEBMIN_FW_TCP_INCOMING \ - < <(tr ' ' '\n' <<< "$WEBMIN_FW_TCP_INCOMING" | sort -un) +# Note: lastpipe is enabled to work around race condition when combining +# readarray directly with process substitution in bash scripts (job control +# must be off) +shopt -s lastpipe + +tr ' ' '\n' <<<"$WEBMIN_FW_TCP_INCOMING" \ + | sort -un \ + | readarray -t WEBMIN_FW_TCP_INCOMING + +# Disable lastpipe again to ensure no unexpected behavior later... +shopt -u lastpipe for conf in /etc/iptables.up.rules /etc/ip6tables.up.rules; do if [[ "$conf" == *"ip6"* ]]; then From dcee63f025656137e0214656640c0729ee0a684c Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 10:00:17 +1000 Subject: [PATCH 06/12] Update fail2ban defaults; longer 'findtime' to 10min (hardened); increase 'maxretry' to 3 (slight easing) --- overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local b/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local index 28eb775e..ccd1b765 100644 --- a/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local +++ b/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local @@ -9,8 +9,8 @@ [DEFAULT] ignoreip = 127.0.0.1/8 ::1 bantime = 3600 -findtime = 10 -maxretry = 2 +findtime = 600 # 10 minutes +maxretry = 3 backend = systemd [sshd] From f92d4d5308e56a32ad392aee3a17e5134730333c Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 11:30:11 +1000 Subject: [PATCH 07/12] Webmin conf - Force ssl/tls and hsts; 30 min session timeout --- conf/turnkey.d/webmin-conf-logging | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/turnkey.d/webmin-conf-logging b/conf/turnkey.d/webmin-conf-logging index c73fd286..c3467647 100755 --- a/conf/turnkey.d/webmin-conf-logging +++ b/conf/turnkey.d/webmin-conf-logging @@ -28,7 +28,9 @@ update_or_add no_tls1_1 1 update_or_add no_tls1_2 update_or_add extracas update_or_add ssl_hsts 1 +update_or_add ssl_enforce 2 # force with hsts - '1' forces ssl but not hsts update_or_add ssl_redirect 1 +update_or_add session_timeout 1800 # 30 minutes # update logfile location update_or_add logfile "$LOG_DIR/miniserv.log" update_or_add errorlog "$LOG_DIR/miniserv.error" From 690455543199f546d6dc62776dce98fdc1bc5cb0 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 15:55:39 +1000 Subject: [PATCH 08/12] Don't install webmin-net by default - works around #2118 --- plans/turnkey/base | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plans/turnkey/base b/plans/turnkey/base index e805ed45..ab598125 100644 --- a/plans/turnkey/base +++ b/plans/turnkey/base @@ -62,7 +62,9 @@ ncurses-term /* support additional $TERM values */ webmin webmin-authentic-theme -webmin-net +// webmin-net causing issues so excluded for now +// see https://github.com/turnkeylinux/tracker/issues/2118 +//webmin-net webmin-software webmin-useradmin webmin-passwd From aaf1c4d402a9eed4c2481bf9bd8186097040b837 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 15:57:37 +1000 Subject: [PATCH 09/12] Install iptables-persistent - resolves issue enabling/disabling firewall via Webmin --- plans/turnkey/base | 1 + 1 file changed, 1 insertion(+) diff --git a/plans/turnkey/base b/plans/turnkey/base index ab598125..634b3cab 100644 --- a/plans/turnkey/base +++ b/plans/turnkey/base @@ -84,6 +84,7 @@ libfile-mimeinfo-perl /* webmin-filemin requires to extract archives */ logrotate iptables +iptables-persistent webmin-firewall webmin-firewall6 fail2ban From 20f20bda49859acc5f2f584d8a3b264ff3fac318 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 16:01:49 +1000 Subject: [PATCH 10/12] Update firewall rule generation for use with 'iptables-persistent' package --- conf/turnkey.d/webmin-fw | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/turnkey.d/webmin-fw b/conf/turnkey.d/webmin-fw index 3e01d5e6..854facaf 100755 --- a/conf/turnkey.d/webmin-fw +++ b/conf/turnkey.d/webmin-fw @@ -17,8 +17,9 @@ tr ' ' '\n' <<<"$WEBMIN_FW_TCP_INCOMING" \ # Disable lastpipe again to ensure no unexpected behavior later... shopt -u lastpipe -for conf in /etc/iptables.up.rules /etc/ip6tables.up.rules; do - if [[ "$conf" == *"ip6"* ]]; then +# iptables-persistent package compatible config +for conf in /etc/iptables/rules.v4 /etc/iptables/rules.v6; do + if [[ "$conf" == *"rules.v6" ]]; then # IPv6 should all accept all ICMPv6 types, not just echo-request # ICMPv6 is essential for neighbour discovery (NDP), router # advertisements, and path MTU - blocking it breaks IPv6 networking From 748dc54c691d6b33a52d62e366f6a5343ad67b61 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 16:27:35 +1000 Subject: [PATCH 11/12] Update TurnKey webmin patch to disable Webmin Let's Encrypt --- .../webmin/usr/local/src/webmin.patch | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/overlays/turnkey.d/webmin/usr/local/src/webmin.patch b/overlays/turnkey.d/webmin/usr/local/src/webmin.patch index cf76bcbb..d27ce764 100644 --- a/overlays/turnkey.d/webmin/usr/local/src/webmin.patch +++ b/overlays/turnkey.d/webmin/usr/local/src/webmin.patch @@ -1,19 +1,25 @@ diff --git a/edit_ssl.cgi b/edit_ssl.cgi -index dd98182..1a4cd77 100755 +index a8b6274..f552dbb 100755 --- a/edit_ssl.cgi +++ b/edit_ssl.cgi -@@ -259,13 +259,14 @@ print ui_tabs_end_tab(); - print ui_tabs_start_tab("mode", "lets"); - print "$text{'ssl_letsdesc'}

\n"; +@@ -261,19 +261,15 @@ print ui_tabs_end_tab(); + # Let's Encrypt form + print ui_tabs_start_tab("mode", "lets"); -my $err = &check_letsencrypt(); +my $err = 1; - if ($err) { -- print "",&text('ssl_letserr', $err),"

\n"; -- print &get_letsencrypt_install_message( -- "/$module_name/edit_ssl.cgi?mode=lets", $text{'ssl_title'}); -- print "

\n"; -- print &text('ssl_letserr2', "../config.cgi?$module_name"),"

\n"; + print $text{'ssl_letsdesc'}; + if (!$err) { +- print &ui_tag('span', +- &ui_details({ +- 'class' => 'inline inlined', +- 'title' => '', +- 'content' => $text{'ssl_letsdesc2'}, +- }))."\n". +- &ui_tag('style', +- ".ui--span>details.inline>summary+span {\n". +- "margin-top: 0;\n". +- "}\n"); + print "Unfortunately the Webmin Let's Encrypt module currrently clashes"; + print " with TurnKey's SSL conf and has been disabled

\n"; + print "

To use Let's Encrypt, please use "; + print "Let's Encrypt plugin docs.

"; } - else { - # Show form to create a cert + print "

\n"; + From 58c6ebc186032cf5762e1280869b85de865f948b Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 20 May 2026 16:36:51 +1000 Subject: [PATCH 12/12] Fail if Webmin LE patch doesn't apply cleanly --- conf/turnkey.d/webmin-lets-enc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/turnkey.d/webmin-lets-enc b/conf/turnkey.d/webmin-lets-enc index a19d84ed..2ae13e0e 100755 --- a/conf/turnkey.d/webmin-lets-enc +++ b/conf/turnkey.d/webmin-lets-enc @@ -3,5 +3,7 @@ # Disable Webmin Let's Encrypt config - via patch cd /usr/share/webmin/webmin +# test patch first; --check exits non-zero if doesn't apply cleanly +git apply --check /usr/local/src/webmin.patch git apply /usr/local/src/webmin.patch rm /usr/local/src/webmin.patch