From 051d77e9f78fca078ba967c05da15924090719a1 Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Wed, 3 Jun 2026 22:24:40 +0000 Subject: [PATCH 1/2] OpenVPN Fixes - update old python inithooks - ensure cipher & auth config are applied --- conf.d/main | 2 +- .../lib/inithooks/bin/openvpn-server-init.sh | 3 + overlay/usr/lib/inithooks/bin/openvpn.py | 86 +++++++++---------- 3 files changed, 45 insertions(+), 46 deletions(-) diff --git a/conf.d/main b/conf.d/main index 3f1a58e..1f6fc05 100755 --- a/conf.d/main +++ b/conf.d/main @@ -6,7 +6,7 @@ OPENSSL_CONF=$EASY_RSA/openssl-easyrsa.cnf SRC=/usr/local/src # enable ip forwarding -sed -i "/^#net.ipv4.ip_forward=1/ s/#//" /etc/sysctl.conf +echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/40-openvpn.conf mkdir -p $EASY_RSA cp -ur /usr/share/easy-rsa/* $EASY_RSA diff --git a/overlay/usr/lib/inithooks/bin/openvpn-server-init.sh b/overlay/usr/lib/inithooks/bin/openvpn-server-init.sh index cef11f4..7860d9e 100755 --- a/overlay/usr/lib/inithooks/bin/openvpn-server-init.sh +++ b/overlay/usr/lib/inithooks/bin/openvpn-server-init.sh @@ -156,4 +156,7 @@ verb 4 # the server will be configured with x.x.x.1 # important: must not be used on your network server $(expand_cidr "$virtual_subnet") + +cipher AES-256-GCM +auth SHA512 EOF diff --git a/overlay/usr/lib/inithooks/bin/openvpn.py b/overlay/usr/lib/inithooks/bin/openvpn.py index 2fcfe40..131a685 100755 --- a/overlay/usr/lib/inithooks/bin/openvpn.py +++ b/overlay/usr/lib/inithooks/bin/openvpn.py @@ -21,16 +21,16 @@ Note: options not specified but required by profile will be asked interactively """ +import getopt import os -from os.path import exists +import subprocess import sys -import getopt -from libinithooks import inithooks_cache +from os.path import exists from random import randint as r -from libinithooks import is_interactive, warn, info +from libinithooks import info, inithooks_cache, is_interactive, warn from libinithooks.dialog_wrapper import Dialog -import subprocess + def fatal(e): print("Error:", e, file=sys.stderr) @@ -39,14 +39,14 @@ def fatal(e): def usage(e=None): if e: print("Error:", e, file=sys.stderr) - print("Syntax: %s [options]" % sys.argv[0], file=sys.stderr) + print(f"Syntax: {sys.argv[0]} [options]", file=sys.stderr) print(__doc__, file=sys.stderr) sys.exit(1) def expand_cidr(cidr): - network, bitcount = cidr.split('/') + network, bitcount = cidr.split("/") # turn / into a 32-long bit array - bits = ('1' * int(bitcount)).ljust(32, '0') + bits = ("1" * int(bitcount)).ljust(32, "0") # split the bit array into 4 bytes bytes_list = [ int(bits[0:8], 2), @@ -54,14 +54,14 @@ def expand_cidr(cidr): int(bits[16:24], 2), int(bits[24:32], 2), ] - + return "{} {}.{}.{}.{}".format(network, *bytes_list) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", - ['help', 'profile=', 'key-email=', 'public-address=', 'virtual-subnet=', - 'private-subnet=']) + ["help", "profile=", "key-email=", "public-address=", "virtual-subnet=", + "private-subnet="]) except getopt.GetoptError as e: usage(e) @@ -70,50 +70,49 @@ def main(): public_address = "" virtual_subnet = "" private_subnet = "" - redirect_client_gateway = "" for opt, val in opts: - if opt in ('-h', '--help'): + if opt in ("-h", "--help"): usage() - elif opt == '--profile': + elif opt == "--profile": profile = val - elif opt == '--key-email': + elif opt == "--key-email": key_email = val - elif opt == '--public-address': + elif opt == "--public-address": public_address = val - elif opt == '--virtual-subnet': + elif opt == "--virtual-subnet": virtual_subnet = val - elif opt == '--private-subnet': + elif opt == "--private-subnet": private_subnet = val - dialog = Dialog('TurnKey Linux - First boot configuration') + dialog = Dialog("TurnKey Linux - First boot configuration") - tun_exists = exists('/dev/net/tun') + tun_exists = exists("/dev/net/tun") if not tun_exists: if is_interactive: - dialog.msgbox('Tun device not created', ''' + dialog.msgbox("Tun device not created", """ Failed to create `/dev/net/tun` device on boot, this is expected when running inside a non-privileged container. -If you are running on an unprivileged container, you will need to create this device on the host.''') +If you are running on an unprivileged container, you will need to create this device on the host.""") else: - warn('Failed to create `/dev/net/tun` device on boot, this is expected when ' - + 'running inside a non-privileged container. If you are ' - + 'running on an unprivileged container, you will need to ' - + 'create this device on the host.') + warn("Failed to create `/dev/net/tun` device on boot, this is expected when " + "running inside a non-privileged container. If you are " + "running on an unprivileged container, you will need to " + "create this device on the host.") else: - info('/dev/net/tun created successfully') + info("/dev/net/tun created successfully") if not profile: profile = dialog.menu( "OpenVPN Profile", "Choose a profile for this server.\n\n* Gateway: clients will be configured to route all\n their traffic through the VPN.", [ - ('server', 'Accept VPN connections from clients'), - ('gateway', 'Accept VPN connections from clients*'), - ('client', 'Initiate VPN connections to a server') + ("server", "Accept VPN connections from clients"), + ("gateway", "Accept VPN connections from clients*"), + ("client", "Initiate VPN connections to a server"), ]) - if not profile in ('server', 'gateway', 'client'): - fatal('invalid profile: %s' % profile) + if profile not in ("server", "gateway", "client"): + fatal(f"invalid profile: {profile}") if profile == "client": return @@ -124,7 +123,7 @@ def main(): "Enter email address for the OpenVPN server key.", "admin@example.com") - inithooks_cache.write('APP_EMAIL', key_email) + inithooks_cache.write("APP_EMAIL", key_email) if not public_address: public_address = dialog.get_input( @@ -132,7 +131,7 @@ def main(): "Enter FQDN or IP address of server reachable by clients", "vpn.example.com") - auto_virtual_subnet = "10.%d.%d.0/24" % (r(2, 254), r(2, 254)) + auto_virtual_subnet = f"10.{r(2, 254)}.{r(2, 254)}.0/24" if not virtual_subnet: virtual_subnet = dialog.get_input( "OpenVPN Virtual Subnet", @@ -152,22 +151,19 @@ def main(): if private_subnet.upper() == "SKIP": private_subnet = "" - cmd = os.path.join(os.path.dirname(__file__), 'openvpn-server-init.sh') + cmd = os.path.join(os.path.dirname(__file__), "openvpn-server-init.sh") subprocess.run([cmd, key_email, public_address, virtual_subnet]) if profile == "gateway": - fh = open("/etc/openvpn/server.conf", "a") - fh.write("# configure clients to route all their traffic through the vpn\n") - fh.write("push \"redirect-gateway def1 bypass-dhcp\"\n\n") - fh.close() + with open("/etc/openvpn/server.conf", "a") as fob: + fob.write("# configure clients to route all their traffic through the vpn\n") + fob.write('push "redirect-gateway def1 bypass-dhcp"\n\n') if private_subnet: - fh = open("/etc/openvpn/server.conf", "a") - fh.write("# push routes to clients to allow them to reach private subnets\n") - for _private_subnet in private_subnet.split(',') : - fh.write("push \"route %s\"\n" % expand_cidr(_private_subnet)) - fh.close() - subprocess.run(['systemctl', 'start', 'openvpn@server']) + with open("/etc/openvpn/server.conf", "a") as fob: + fob.write("# push routes to clients to allow them to reach private subnets\n") + fob.writelines(f'push "route {expand_cidr(_private_subnet)}"\n' for _private_subnet in private_subnet.split(",")) + subprocess.run(["systemctl", "start", "openvpn@server"]) if __name__ == "__main__": main() From 5247fe18d4bf1392ebe1a001c361c0aded3c03a3 Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Fri, 26 Jun 2026 05:06:08 +0000 Subject: [PATCH 2/2] update changelog --- changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog b/changelog index 8184817..5c77524 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,9 @@ +turnkey-openvpn-19.0 (1) turnkey; urgency=low + + * Install OpenVPN from Debian repos - v2.6.14. + + -- Stefan Davis Fri, 26 Jun 2026 05:05:23 +0000 + turnkey-openvpn-18.1 (1) turnkey; urgency=low * v18.1 rebuild - includes latest Debian & TurnKey packages.