aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2025-09-29 00:53:24 +0200
committerJan Tuomi <jan@jantuomi.fi>2025-09-29 00:53:24 +0200
commit7c5eae9294994e59a5176eba21093ecd6cdfcf63 (patch)
treea3d7d0a34d6e4b9a773cd85b99afc9eca5b5bb9c
parentcc1b02f99e457d2a5a440698e9bae1ca30f408e1 (diff)
Improve jails
-rw-r--r--playbook.yml3
-rw-r--r--tasks/general.yml9
-rw-r--r--tasks/network.yml23
-rw-r--r--templates/etc_crontab.j23
-rw-r--r--templates/etc_jail.conf.j220
-rw-r--r--templates/etc_pf.conf.j29
-rw-r--r--templates/etc_rc.conf.j216
-rw-r--r--templates/usr_local_bin_do_dyndns.sh.j265
-rw-r--r--templates/usr_local_bin_logto.sh.j247
-rw-r--r--templates/usr_local_etc_rc.d_do_dyndns.j253
10 files changed, 110 insertions, 138 deletions
diff --git a/playbook.yml b/playbook.yml
index 743cba8..7faac38 100644
--- a/playbook.yml
+++ b/playbook.yml
@@ -28,7 +28,7 @@
jails:
- { name: ingress, num: 1 }
- { name: postgres, num: 2 }
- - { name: irc_thelounge, num: 3 }
+ - { name: backup, num: 3 }
- { name: taulubot, num: 4 }
- { name: veetibot, num: 5 }
- { name: hommabot, num: 6 }
@@ -39,6 +39,7 @@
- { name: spliit, num: 11 }
- { name: stirling-pdf, num: 12 }
- { name: ente, num: 13 }
+ - { name: irc_thelounge, num: 14 }
static_sites:
- { site: "homepage", host: "jan.systems", tls: false }
- { site: "homepage", host: "pursotin.jan.systems", tls: true }
diff --git a/tasks/general.yml b/tasks/general.yml
index 9361217..46f04a1 100644
--- a/tasks/general.yml
+++ b/tasks/general.yml
@@ -7,6 +7,7 @@
- dma
- jq
- curl
+ - bash
- name: Set up periodic.conf
template:
@@ -57,3 +58,11 @@
name: cron
state: restarted
when: etc_crontab.changed
+
+- name: Install logto
+ template:
+ src: usr_local_bin_logto.sh.j2
+ dest: /usr/local/bin/logto
+ owner: root
+ group: wheel
+ mode: "0755"
diff --git a/tasks/network.yml b/tasks/network.yml
index a8749a7..15c4494 100644
--- a/tasks/network.yml
+++ b/tasks/network.yml
@@ -12,7 +12,7 @@
when: resolv_conf.changed
- name: Restart networking if interface configuration changed
- shell: service netif restart && service routing restart && service dhclient restart wan0
+ shell: service netif restart && service routing restart
when: rc_conf.changed or resolv_conf.changed
- name: Set up sshd
@@ -83,24 +83,3 @@
group: wheel
mode: "0755"
register: do_dyndns_sh
-
-- name: Set up /usr/local/etc/rc.d/do_dyndns
- template:
- src: usr_local_etc_rc.d_do_dyndns.j2
- dest: /usr/local/etc/rc.d/do_dyndns
- owner: root
- group: wheel
- mode: "0755"
- register: do_dyndns_rc
-
-- name: Start do_dyndns
- service:
- name: do_dyndns
- state: started
- register: do_dyndns_start
-
-- name: Restart do_dyndns
- service:
- name: do_dyndns
- state: restarted
- when: not do_dyndns_start.changed and (do_dyndns_sh.changed or do_dyndns_rc.changed)
diff --git a/templates/etc_crontab.j2 b/templates/etc_crontab.j2
index f7a59d9..a6c48e4 100644
--- a/templates/etc_crontab.j2
+++ b/templates/etc_crontab.j2
@@ -20,3 +20,6 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
# Adjust the time zone if the CMOS clock keeps local time, as opposed to
# UTC time. See adjkerntz(8) for details.
1,31 0-5 * * * root adjkerntz -a
+
+# Update dynamic DNS
+*/1 * * * * root logto -e /var/log/do_dyndns.err /usr/local/bin/do_dyndns.sh
diff --git a/templates/etc_jail.conf.j2 b/templates/etc_jail.conf.j2
index 86da8de..708e5c1 100644
--- a/templates/etc_jail.conf.j2
+++ b/templates/etc_jail.conf.j2
@@ -1,18 +1,22 @@
# STARTUP/LOGGING/VNET
-$epair = "epair${num}"; # epairXa is host end, epairXb is jail end
+$tmp_epair = "epair${num}";
+$epl = "epl${num}"; # eplXa is host end (local network bridge), eplXb is jail end.
+ # The corresponding pubnet interface is epwX, but that's not created for all jails.
vnet;
-vnet.interface = "${epair}b";
+vnet.interface = "${epl}b";
persist;
-exec.prestart += "ifconfig $epair create || echo 'Failed to create $epair'";
-exec.prestart += "ifconfig ${epair}a up";
-exec.prestart += "ifconfig bridge0 addm ${epair}a";
+exec.prestart += "ifconfig $tmp_epair create || echo 'Failed to create $tmp_epair'";
+exec.prestart += "ifconfig ${tmp_epair}a name ${epl}a";
+exec.prestart += "ifconfig ${tmp_epair}b name ${epl}b";
+exec.prestart += "ifconfig ${epl}a up";
+exec.prestart += "ifconfig brlan0 addm ${epl}a";
exec.clean;
exec.start = "/bin/sh /etc/rc";
-exec.poststart = "jexec ${name} ifconfig ${epair}b 192.168.2.${num}/16";
+exec.poststart = "jexec ${name} ifconfig ${epl}b 192.168.2.${num}/16";
exec.poststart += "jexec ${name} route add default 192.168.0.1 || echo 'Failed to add default route'";
exec.stop = "/bin/sh /etc/rc.shutdown";
-exec.poststop += "ifconfig ${epair}b -vnet $name"; # workaround to bug 238326: move ${epair}b from the jail to the host when stopping jail services
-exec.poststop += "ifconfig ${epair}b destroy"; # and then destroy the pair by destroying one end of it
+exec.poststop += "ifconfig ${epl}b -vnet $name"; # workaround to bug 238326: move ${epl}b from the jail to the host when stopping jail services
+exec.poststop += "ifconfig ${epl}b destroy"; # and then destroy the pair by destroying one end of it
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
diff --git a/templates/etc_pf.conf.j2 b/templates/etc_pf.conf.j2
index 0bb7fef..a439702 100644
--- a/templates/etc_pf.conf.j2
+++ b/templates/etc_pf.conf.j2
@@ -7,13 +7,6 @@ set skip on lo
set block-policy return
scrub in
-# Redirect HTTP to ingress jail
-# TODO: fix these redirects, they seem to not work
-rdr on $wan_if proto tcp from any to ($wan_if) port 80 -> $jail_ingress_ip port 80
-rdr on $wan_if proto tcp from any to ($wan_if) port 443 -> $jail_ingress_ip port 443
-rdr on $lan_if proto tcp from any to ($lan_if) port 80 -> $jail_ingress_ip port 80
-rdr on $lan_if proto tcp from any to ($lan_if) port 443 -> $jail_ingress_ip port 443
-
# Default block all
block in all
@@ -21,7 +14,7 @@ block in all
pass out all keep state
# Allow inbound HTTP/HTTPS on both interfaces
-pass in on $wan_if proto tcp from any to ($wan_if) port { 80, 443 } keep state
+pass in on $wan_if proto tcp from any to any port { 80, 443 } keep state
pass in on $lan_if proto tcp from any to ($lan_if) port { 80, 443 } keep state
# Allow SSH only on lan0
diff --git a/templates/etc_rc.conf.j2 b/templates/etc_rc.conf.j2
index 195e599..03b5d10 100644
--- a/templates/etc_rc.conf.j2
+++ b/templates/etc_rc.conf.j2
@@ -8,14 +8,17 @@ moused_nondefault_enable="NO"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"
zfs_enable="YES"
+defaultrouter="192.168.0.1"
+cloned_interfaces="bridge0 bridge1"
ifconfig_igc0_name="lan0"
ifconfig_igc1_name="wan0"
+ifconfig_bridge0_name="brlan0"
+ifconfig_bridge1_name="brwan0"
ifconfig_lan0="inet {{ lan_ipv4_cidr }}"
ifconfig_lan0_ipv6="inet6 accept_rtadv"
-ifconfig_wan0="DHCP"
-ifconfig_wan0_ipv6="inet6 accept_rtadv"
-cloned_interfaces="bridge0"
-ifconfig_bridge0="addm lan0 up"
+ifconfig_wan0="up"
+ifconfig_brlan0="addm lan0 up"
+ifconfig_brwan0="addm wan0 up"
zpool_gpt_labels_enable="YES"
smartd_enable="YES"
pf_enable="YES"
@@ -24,12 +27,7 @@ syslogd_flags="-s"
jail_enable="YES"
jail_parallel_start="YES"
jail_reverse_stop="YES"
-nginx_enable="YES"
clear_tmp_enable="YES"
cleanvar_enable="YES"
auditd_enable="YES"
devd_enable="YES"
-do_dyndns_enable="YES"
-do_dyndns_domain="jan.systems"
-do_dyndns_hostname="pursotin"
-do_dyndns_if4="wan0"
diff --git a/templates/usr_local_bin_do_dyndns.sh.j2 b/templates/usr_local_bin_do_dyndns.sh.j2
index 1b080b7..f23d635 100644
--- a/templates/usr_local_bin_do_dyndns.sh.j2
+++ b/templates/usr_local_bin_do_dyndns.sh.j2
@@ -1,51 +1,42 @@
#!/bin/sh
set -eu
-: "${DO_DYNDNS_DOMAIN:?DO_DYNDNS_DOMAIN must be set}"
-: "${DO_DYNDNS_HOSTNAME:?DO_DYNDNS_HOSTNAME must be set}"
-: "${DO_DYNDNS_IF4:?DO_DYNDNS_IF4 must be set}"
-: "${DO_DYNDNS_INTERVAL:?DO_DYNDNS_INTERVAL must be set}"
-: "${DO_DYNDNS_AUTH_FILE:?DO_DYNDNS_AUTH_FILE must be set}"
+DOMAIN="jan.systems"
+HOSTNAME="pursotin"
+AUTH_FILE="/usr/local/etc/do_dyndns_auth"
+IF4="$(jexec ingress ifconfig epw1b)"
-if [ ! -r "$DO_DYNDNS_AUTH_FILE" ]; then
- echo "[ERROR] Auth file '$DO_DYNDNS_AUTH_FILE' not readable" >&2
- exit 1
-fi
+# END OF CONFIG
+
+info() {
+ echo "$(date) [INFO]" $@
+}
-DOMAIN="$DO_DYNDNS_DOMAIN"
-HOSTNAME="$DO_DYNDNS_HOSTNAME"
-IF4="$DO_DYNDNS_IF4"
-INTERVAL="$DO_DYNDNS_INTERVAL"
+err() {
+ >&2 echo "$(date) [ERROR]" $@
+}
+
+if [ ! -r "$AUTH_FILE" ]; then
+ err "Auth file '$AUTH_FILE' not readable"
+ exit 1
+fi
-while :; do
- IP4=$(ifconfig "$IF4" | awk '/inet / { print $2 }' | head -n1)
- DIGITALOCEAN_TOKEN=$(awk '{$1=$1; print}' "$DO_DYNDNS_AUTH_FILE")
+IP4=$(echo "$IF4" | awk '/inet / { print $2 }' | head -n1)
+DIGITALOCEAN_TOKEN=$(awk '{$1=$1; print}' "$AUTH_FILE")
- echo "[INFO] Updating A record for hostname $HOSTNAME in domain $DOMAIN → $IP4"
+info "Updating A record for hostname $HOSTNAME in domain $DOMAIN → $IP4"
- RECORD_ID=$(curl -s -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
- "https://api.digitalocean.com/v2/domains/$DOMAIN/records?per_page=999999" |
- jq -r ".domain_records[] | select(.type==\"A\" and .name==\"$HOSTNAME\") | .id")
+RECORD_ID=$(curl -s -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
+"https://api.digitalocean.com/v2/domains/$DOMAIN/records?per_page=999999" |
+jq -r ".domain_records[] | select(.type==\"A\" and .name==\"$HOSTNAME\") | .id")
- if [ -n "$RECORD_ID" ]; then
+if [ -n "$RECORD_ID" ]; then
curl -s -X PUT \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"data\":\"$IP4\"}" \
"https://api.digitalocean.com/v2/domains/$DOMAIN/records/$RECORD_ID" > /dev/null
- echo "[INFO] Record $RECORD_ID updated"
- else
- echo "[WARN] No A record found for hostname \"$HOSTNAME\" in domain \"$DOMAIN\". Skipping."
- fi
-
- SLEEP_SEC=$(printf "%s\n" "$INTERVAL" | awk '
- /^[0-9]+s$/ { gsub(/s$/, ""); print $0; exit }
- /^[0-9]+m$/ { gsub(/m$/, ""); print $0 * 60; exit }
- /^[0-9]+h$/ { gsub(/h$/, ""); print $0 * 3600; exit }
- /^[0-9]+d$/ { gsub(/d$/, ""); print $0 * 86400; exit }
- /^[0-9]+$/ { print $0; exit }
- { print "invalid"; exit 1 }
- ')
-
- sleep "$SLEEP_SEC"
-done
+ info "Record $RECORD_ID updated"
+else
+ err "No A record found for hostname \"$HOSTNAME\" in domain \"$DOMAIN\". Skipping."
+fi
diff --git a/templates/usr_local_bin_logto.sh.j2 b/templates/usr_local_bin_logto.sh.j2
new file mode 100644
index 0000000..9bb5aa1
--- /dev/null
+++ b/templates/usr_local_bin_logto.sh.j2
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+set -ue
+
+# Wrapper for logging to file and prepending a timestamp.
+# By default writes both stdout and stderr to the log file.
+
+usage() {
+ echo "Usage: logto [-s|-e] <log_file> <command>"
+ echo "Flags:"
+ echo " -s: Write only stdout to the log file."
+ echo " -e: Write only stderr to the log file."
+ echo ""
+ echo "Example usage:"
+ echo " logto /var/log/my.log run some command"
+ exit 1
+}
+
+mode="all"
+
+while getopts "se" opt; do
+ case $opt in
+ s) mode="stdout" ;;
+ e) mode="stderr" ;;
+ *) usage ;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ $# -lt 2 ]; then
+ usage
+fi
+
+log_file="$1"
+shift
+
+if [ "$mode" = "stdout" ]; then
+ out=$(2>/dev/null $@)
+elif [ "$mode" = "stderr" ]; then
+ out=$(2>&1 >/dev/null $@)
+else
+ out=$(2>&1 $@)
+fi
+
+if [ ! -z "$out" ]; then
+ echo "$(date +"%Y-%m-%dT%H:%M:%S%z")" "$out" >>"$log_file"
+fi
diff --git a/templates/usr_local_etc_rc.d_do_dyndns.j2 b/templates/usr_local_etc_rc.d_do_dyndns.j2
deleted file mode 100644
index 6c4c18e..0000000
--- a/templates/usr_local_etc_rc.d_do_dyndns.j2
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-#
-# PROVIDE: do_dyndns
-# REQUIRE: NETWORKING
-# KEYWORD: shutdown
-
-. /etc/rc.subr
-
-name="do_dyndns"
-rcvar=do_dyndns_enable
-
-extra_commands="status"
-rcvars="do_dyndns_enable do_dyndns_domain do_dyndns_hostname do_dyndns_if4 do_dyndns_interval do_dyndns_auth_file"
-stop_cmd="do_dyndns_stop"
-
-load_rc_config $name
-
-: "${do_dyndns_enable:=NO}"
-: "${do_dyndns_interval:=1m}"
-: "${do_dyndns_hostname:=@}"
-: "${do_dyndns_auth_file:=/usr/local/etc/do_dyndns_auth}"
-
-pidfile="/var/run/${name}.pid"
-logfile="/var/log/${name}"
-
-command="/usr/sbin/daemon"
-command_args="-cfr -P ${pidfile} -o ${logfile} /bin/sh -c '
- export PATH=\"/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\"
- export DO_DYNDNS_DOMAIN=\"${do_dyndns_domain}\"
- export DO_DYNDNS_HOSTNAME=\"${do_dyndns_hostname}\"
- export DO_DYNDNS_IF4=\"${do_dyndns_if4}\"
- export DO_DYNDNS_INTERVAL=\"${do_dyndns_interval}\"
- export DO_DYNDNS_AUTH_FILE=\"${do_dyndns_auth_file}\"
-
- exec /usr/local/bin/do_dyndns.sh
-'"
-
-do_dyndns_stop() {
- echo "Stopping ${name} with SIGINT..."
- if [ -f "${pidfile}" ]; then
- kill -INT "$(cat "${pidfile}")"
- sleep 5
- if kill -0 "$(cat "${pidfile}")" 2>/dev/null; then
- echo "Process didn't exit, sending SIGKILL..."
- kill -KILL "$(cat "${pidfile}")"
- fi
- rm -f "${pidfile}"
- else
- echo "${name}: no pidfile found"
- fi
-}
-
-run_rc_command "$1"