diff --git a/gate-traefik/assets/etc/network/.pve-ignore.interfaces b/gate-traefik/assets/etc/network/.pve-ignore.interfaces new file mode 100644 index 0000000..e69de29 diff --git a/gate-traefik/assets/etc/traefik.d/ssh.yml b/gate-traefik/assets/etc/traefik.d/ssh.yml new file mode 100644 index 0000000..c46fc23 --- /dev/null +++ b/gate-traefik/assets/etc/traefik.d/ssh.yml @@ -0,0 +1,13 @@ +tcp: + routers: + ssh: + entryPoints: + - ssh2 + service: ssh + rule: "HostSNI(`*`)" + + services: + ssh: + loadBalancer: + servers: + - address: ssh.srv:22 diff --git a/gate-traefik/assets/etc/traefik.d/wireguard.yml b/gate-traefik/assets/etc/traefik.d/wireguard.yml new file mode 100644 index 0000000..178bc9e --- /dev/null +++ b/gate-traefik/assets/etc/traefik.d/wireguard.yml @@ -0,0 +1,20 @@ +udp: + routers: + wireguard-admin: + entryPoints: + - wireguard2 + service: wireguard-admin + wireguard-client: + entryPoints: + - wireguard + service: wireguard-client + + services: + wireguard-admin: + loadBalancer: + servers: + - address: wireguard.srv:51820 + wireguard-client: + loadBalancer: + servers: + - address: wireguard-client.srv:51820 diff --git a/gate-traefik/assets/root/routing.sh b/gate-traefik/assets/root/routing.sh new file mode 100644 index 0000000..8630a58 --- /dev/null +++ b/gate-traefik/assets/root/routing.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# IP Forwarding +# add to wan interface in: /etc/network/interfaces: +# post-up echo 1 > /proc/sys/net/ipv4/ip_forward +# or: +# # sysctl -w net.ipv4.ip_forward=1 +# + + +# Enable traefik config parsing... +TRAEFIC=1 + + +# Enable iptables +# # apk add iptables iptables-doc +# # rc-update add iptables +# # rc-service iptables save + +LAN=lan +WAN=wan + + +# keep connections while configuring... +iptables -P INPUT ACCEPT +iptables -P OUTPUT ACCEPT +iptables -P FORWARD ACCEPT + + +# Flush iptables rules +iptables -F +iptables -X +iptables -t nat -F + + +# Statefull connections +iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + +# Loop-back rules +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# DNS +iptables -A INPUT -p udp --sport 53 -j ACCEPT +iptables -A INPUT -p udp --dport 53 -j ACCEPT + +# ICMP +#iptables -A INPUT -i $WAN -p icmp -j ACCEPT +iptables -A INPUT -p icmp -j ACCEPT + + +# Traefik +if ! [ -z $TRAEFIC ] ; then + # NOTE: we only open ports here not caring about addresses... + IFS=$'\n' + RULES=($( + cat /etc/traefik/traefik.yaml \ + | grep '^[^#]*address:' \ + | grep -o "\'.*\'")) + for addr in "${RULES[@]}" ; do + addr=${addr:1:-1} + host=${addr/:*} + port=${addr/*:} + + udp= + tcp= + if [[ $port == *udp* ]] ; then + udp=1 + fi + if [[ $port == *tcp* ]] ; then + tcp=1 + fi + if [ -z $tcp ] && [ -z $udp ] ; then + tcp=1 + udp=1 + fi + port=${port/\/*/} + + if ! [ -z $udp ] ; then + iptables -A INPUT -p udp --dport $port -j ACCEPT + fi + if ! [ -z $tcp ] ; then + iptables -A INPUT -p tcp --dport $port -j ACCEPT + fi + done +fi + + + +# NAT +iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE + + + +# Default policies +iptables -P INPUT DROP +iptables -P OUTPUT ACCEPT +# XXX do we actually need this??? +# ...uncommenting this breaks forwarding... +#iptables -P FORWARD DROP diff --git a/gate-traefik/make.sh b/gate-traefik/make.sh new file mode 100644 index 0000000..b513765 --- /dev/null +++ b/gate-traefik/make.sh @@ -0,0 +1,158 @@ +#!/usr/bin/bash +#---------------------------------------------------------------------- + +source ../.pct-helpers + + +#---------------------------------------------------------------------- + +UPDATE_ON_LAN=1 +TIMEOUT=5 +TMP_PASS_LEN=32 + +TEMPLATE_DIR=templates +ASSETS_DIR=assets + +# EMAIL= +# DOMAIN= +# ID= +# CTHOSTNAME= +# WAN_IP= +# WAN_GATE= +# ROOTPASS= + +DFL_EMAIL=user@example.com +DFL_DOMAIN=example.com +DFL_ID=500 +DFL_CTHOSTNAME=gate-test +DFL_WAN_IP=192.168.1.101/24 +DFL_WAN_GATE=192.168.1.252 + +TMP_PASS=$(cat /dev/urandom | base64 | head -c ${TMP_PASS_LEN:=32}) + + +#---------------------------------------------------------------------- + +[ -z $EMAIL ] \ + && read -ep "Email: " -i "$DFL_EMAIL" EMAIL +EMAIL=${EMAIL:=$DFL_EMAIL} +[ -z $DOMAIN ] \ + && read -ep "Domain: " -i "$DFL_DOMAIN" DOMAIN +DOMAIN=${DOMAIN:=$DFL_DOMAIN} +[ -z $ID ] \ + && read -ep "ID: " -i "$DFL_ID" ID +[ -z $CTHOSTNAME ] \ + && read -ep "Hostname: " -i "$DFL_CTHOSTNAME" CTHOSTNAME +[ -z $WAN_IP ] \ + && read -ep "WAN ip: " -i "$DFL_WAN_IP" WAN_IP +[ -z $WAN_GATE ] \ + && read -ep "WAN gateway: " -i "$DFL_WAN_GATE" WAN_GATE +if [ -z $ROOTPASS ] ; then + read -sep "root password (Enter to skip): " PASS1 + echo + if [ $PASS1 ] ; then + read -sep "retype root password: " PASS2 + echo + if [[ $PASS1 != $PASS2 ]] ; then + echo "ERR: passwords do not match." + exit 1 + fi + PASS=$PASS1 + fi +else + PASS=$ROOTPASS +fi + + +#---------------------------------------------------------------------- + +echo Building config... +TEMPLATES=($(find "$TEMPLATE_DIR" -type f)) +for file in "${TEMPLATES[@]}" ; do + file=${file#${TEMPLATE_DIR}} + echo Generating: ${file}... + cat "${TEMPLATE_DIR}/${file}" \ + | sed \ + -e 's/\${EMAIL}/'$EMAIL'/' \ + -e 's/\${DOMAIN}/'$DOMAIN'/' \ + -e 's/\${CTHOSTNAME}/'$CTHOSTNAME'/' \ + -e 's/\${WAN_IP}/'${WAN_IP/\//\\/}'/' \ + -e 's/\${WAN_GATE}/'$WAN_GATE'/' \ + > "${ASSETS_DIR}/${file}" +done + + +#---------------------------------------------------------------------- + +echo Creating CT... + +TEMPLATE=($(ls /var/lib/vz/template/cache/alpine-3.18*.tar.xz)) + +@ pct create $ID \ + ${TEMPLATE[-1]} \ + --hostname $CTHOSTNAME \ + --memory 128 \ + --swap 128 \ + --net0 name=lan,bridge=vmbr0,firewall=1,ip=dhcp,type=veth \ + --net1 name=admin,bridge=vmbr1,firewall=1,type=veth \ + --net2 name=wan,bridge=vmbr2,firewall=1${WAN_GATE:+,gw=${WAN_GATE}}${WAN_IP:+,ip=${WAN_IP}},type=veth \ + --storage local-lvm \ + --rootfs local-lvm:0.5 \ + --unprivileged 1 \ + --password="$TMP_PASS" \ + --start 1 \ +|| exit 1 + + +# wait for network to initialize... +sleep $TIMEOUT +if [ $UPDATE_ON_LAN ] ; then + tries=5 + while ! @ lxc-attach $ID ifdown wan 2> /dev/null ; do + tries=$(( tries - 1 )) + if [[ $tries == "0" ]] ; then + echo Giving up. + break + fi + echo Waiting for networking to start... + sleep $TIMEOUT + done +fi + + +echo Setting root password... +if [ $PASS ] ; then + echo "root:$PASS" \ + | @ lxc-attach $ID chpasswd +fi + +echo Updating container... +@ lxc-attach $ID apk update +@ lxc-attach $ID apk upgrade + +echo Installing dependencies... +@ lxc-attach $ID apk add bash iptables traefik + +echo Copying assets... +@ pct-push-r $ID ./assets / + +echo Setup: traefik... +@ lxc-attach $ID rc-update add traefik +@ lxc-attach $ID rc-service traefik start + +echo Setup: iptables... +@ lxc-attach $ID rc-update add iptables +@ lxc-attach $ID bash /root/routing.sh +@ lxc-attach $ID rc-service iptables save +@ lxc-attach $ID rc-service iptables start + + +[ $UPDATE_ON_LAN ] \ + && @ lxc-attach $ID ifup wan + + +echo Done. + + +#---------------------------------------------------------------------- +# vim:set ts=4 sw=4 : diff --git a/gate-traefik/templates/etc/network/interfaces b/gate-traefik/templates/etc/network/interfaces new file mode 100644 index 0000000..9dd35da --- /dev/null +++ b/gate-traefik/templates/etc/network/interfaces @@ -0,0 +1,18 @@ +auto lo +iface lo inet loopback +iface lo inet6 loopback + +auto lan +iface lan inet dhcp + post-up echo 1 > /proc/sys/net/ipv4/ip_forward + hostname $(hostname) + +auto admin +iface admin inet dhcp + hostname $(hostname) + +auto wan +iface wan inet static + address ${WAN_IP} + gateway ${WAN_GATE} + hostname $(hostname) diff --git a/gate-traefik/templates/etc/traefik.d/dashboard.yml b/gate-traefik/templates/etc/traefik.d/dashboard.yml new file mode 100644 index 0000000..b0b888b --- /dev/null +++ b/gate-traefik/templates/etc/traefik.d/dashboard.yml @@ -0,0 +1,15 @@ +#http: +# routers: +# dashboard: +# entryPoints: +# - traefik +# rule: Host(``) +# service: api@internal +## middlewares: +## - auth +## middlewares: +## auth: +## basicAuth: +## users: +## - "test:" +## - "test2:" diff --git a/gate-traefik/templates/etc/traefik.d/gitea.yml b/gate-traefik/templates/etc/traefik.d/gitea.yml new file mode 100644 index 0000000..9b38414 --- /dev/null +++ b/gate-traefik/templates/etc/traefik.d/gitea.yml @@ -0,0 +1,29 @@ +tcp: + routers: + gitea: + entryPoints: + - ssh + service: gitea + rule: "HostSNI(`*`)" + + services: + gitea: + loadBalancer: + servers: + - address: gitea.srv:22 + +http: + routers: + gitea: + entryPoints: + - https + service: gitea + rule: "Host(`${DOMAIN}`)" + tls: + certResolver: letsEncrypt + + services: + gitea: + loadBalancer: + servers: + - url: https://gitea.srv/ diff --git a/gate-traefik/templates/etc/traefik.d/nextcloud.yml b/gate-traefik/templates/etc/traefik.d/nextcloud.yml new file mode 100644 index 0000000..19f1c25 --- /dev/null +++ b/gate-traefik/templates/etc/traefik.d/nextcloud.yml @@ -0,0 +1,15 @@ +http: + routers: + nextcloud: + entryPoints: + - https + service: nextcloud + rule: "Host(`nc.${DOMAIN}`)" + tls: + certResolver: letsEncrypt + + services: + nextcloud: + loadBalancer: + servers: + - url: https://nextcloud.srv/ diff --git a/gate-traefik/templates/etc/traefik/traefik.yaml b/gate-traefik/templates/etc/traefik/traefik.yaml new file mode 100644 index 0000000..8eab26a --- /dev/null +++ b/gate-traefik/templates/etc/traefik/traefik.yaml @@ -0,0 +1,67 @@ +global: + checkNewVersion: false + sendAnonymousUsage: false + +log: + filePath: /var/log/traefik/traefik.log +# compress: 3 +accessLog: + filePath: /var/log/traefik/access.log +# compress: 3 + +entryPoints: + ssh: + address: ':22' + ssh2: + address: ':23' + openvpn: + address: ':1194/udp' + openvpn2: + address: ':5555/udp' + wireguard: + address: ':51820/udp' + wireguard2: + address: ':51821/udp' + http: + address: ':80' + http: + redirections: + entryPoint: + to: https + scheme: https + permanent: true + https: + address: ':443' + + traefik: + address: ':8080' + + +api: + dashboard: true + insecure: true + + +pilot: + dashboard: false + + +ping: {} + + +providers: + file: + directory: /etc/traefik.d/ + watch: true + + +serversTransport: + insecureSkipVerify: true + + + +certificatesResolvers: + letsEncrypt: + acme: + email: '${EMAIL}' + storage: '/etc/traefik/acme.json'