From 8e9097672efd5098280736bf1b3a92840c7135b2 Mon Sep 17 00:00:00 2001 From: maxklema Date: Fri, 20 Jun 2025 21:40:42 -0400 Subject: [PATCH 01/11] added support for variable number of ports. Removed HTTP port assignment --- intern-nginx/port_map.js | 36 +---------- intern-phxdc-pve1/register-container.sh | 86 +++++++++++++++++++------ 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/intern-nginx/port_map.js b/intern-nginx/port_map.js index b0fadd37..c0c1d5a1 100644 --- a/intern-nginx/port_map.js +++ b/intern-nginx/port_map.js @@ -1,8 +1,9 @@ // /etc/nginx/port_map.js // This is a reverse proxy configuration for Nginx that uses JavaScript to dynamically -// map subdomains to specific ports and IP addresses based on a JSON file. +// map subdomains to specific IP addresses based on a JSON file. // Code is based off of bluehive-testflight's port_map.js // Last updated: 06-08-2025 Carter Myers + var fs = require('fs'); var filePath = "/etc/nginx/port_map.json"; var cachedMapping = null; @@ -27,37 +28,6 @@ function extractSubdomain(r) { return match[1]; } -function portLookup(r) { - if (cachedMapping === null && !loadMapping()) { - r.error("Failed to load port mapping file."); - r.return(500); - return; - } - - var subdomain = extractSubdomain(r); - if (!subdomain) { - r.return(500); - return; - } - - var entry = cachedMapping[subdomain]; - if (!entry) { - if (!loadMapping()) { - r.error("Reload failed."); - r.return(500); - return; - } - entry = cachedMapping[subdomain]; - if (!entry) { - r.error("No entry found for subdomain: " + subdomain); - r.return(500); - return; - } - } - - return entry.port.toString(); // Always return string -} - function ipLookup(r) { if (cachedMapping === null && !loadMapping()) { r.error("Failed to load port mapping file."); @@ -89,4 +59,4 @@ function ipLookup(r) { return entry.ip; } -export default { portLookup, ipLookup }; \ No newline at end of file +export default { ipLookup }; \ No newline at end of file diff --git a/intern-phxdc-pve1/register-container.sh b/intern-phxdc-pve1/register-container.sh index 23a00ef5..4b0b6e96 100644 --- a/intern-phxdc-pve1/register-container.sh +++ b/intern-phxdc-pve1/register-container.sh @@ -1,13 +1,10 @@ #!/bin/bash -# /var/lib/vz/snippets/register-container.sh -# This script registers a Proxmox container with the host's NGINX proxy and assigns it an available HTTP and SSH port. -# Last updated: 06-08-2025 Carter Myers -# ---------------------------------------- set -euo pipefail -set -x CTID="$1" +ADDITIONAL_PROTOCOLS="$2" #Optional + if [ -z "$CTID" ]; then echo "Usage: $0 " exit 1 @@ -19,7 +16,7 @@ exec > >(tee -a "$LOGFILE") 2>&1 echo "---- Hookscript started at $(date) ----" echo "⏳ Waiting for container to boot and get DHCP lease..." -sleep 10 +#sleep 10 # Extract IP container_ip="" @@ -37,26 +34,22 @@ fi hostname=$(pct exec "$CTID" -- hostname) -# Get available HTTP port (3000–3999) -used_http_ports=$(ssh root@10.15.20.69 'jq -r ".[] | .port" /etc/nginx/port_map.json 2>/dev/null || echo ""') -http_port=$(comm -23 <(seq 3000 3999 | sort) <(echo "$used_http_ports" | sort) | head -n 1) - -# Check if this container already has a port assigned in PREROUTING +# Check if this container already has a SSH port assigned in PREROUTING existing_ssh_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:22" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) if [[ -n "$existing_ssh_port" ]]; then - echo "ℹ️ Container already has SSH port $existing_ssh_port" + echo "ℹ️ Container already has SSH port $existing_ssh_port" ssh_port="$existing_ssh_port" else # Get used SSH ports - used_ssh_ports=$(iptables -t nat -S PREROUTING | awk -F'--dport ' '/--dport / {print $2}' | awk '{print $1}') + used_ssh_ports=$(iptables -t nat -S PREROUTING | awk -F'--dport ' '/--dport / {print $2}' | awk '/22$/' | awk '{print $1}') ssh_port=$(comm -23 <(seq 2222 2999 | sort) <(echo "$used_ssh_ports" | sort) | head -n 1) if [[ -z "$ssh_port" ]]; then echo "❌ No available SSH ports found" exit 2 fi - +# # Add PREROUTING rule iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport "$ssh_port" -j DNAT --to-destination "$container_ip:22" @@ -64,22 +57,75 @@ else iptables -t nat -A POSTROUTING -o vmbr0 -p tcp -d "$container_ip" --dport 22 -j MASQUERADE fi +# Take input file of protocols, check if the container already has a port assigned for those protocols in PREROUTING + +# Store all protocols and ports to write to JSON list later. + +list_all_protocols=() +list_all_ports=() + +while read line; do + + protocol=$(echo "$line" | awk '{print $1}') + underlying_protocol=$(echo "$line" | awk '{print $2}') + default_port_number=$(echo "$line" | awk '{print $3}') + + protocol_port="" + existing_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:$default_port_number" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) + + if [[ -n "$existing_port" ]]; then + # Port already exists, so just assign it to protocol_port + echo "ℹ️ This Container already has a $protocol port at $existing_port" + protocol_port="$existing_port" + else + used_protocol_ports=$(iptables -t nat -S PREROUTING | awk -F'--dport ' '/--dport / {print $2}' | awk '{print $1}') + protocol_port=$(comm -23 <(seq 10001 29999 | sort) <(echo "$used_protocol_ports" | sort) | head -n 1 || true) + + if [[ -z "protocol_port" ]]; then + echo "❌ No available $protocol ports found" + exit 2 + fi + + # Add PREROUTING rule + iptables -t nat -A PREROUTING -i vmbr0 -p "$underlying_protocol" --dport "$protocol_port" -j DNAT --to-destination "$container_ip:$default_port_number" + + # Add POSTROUTING rule + iptables -t nat -A POSTROUTING -o vmbr0 -p "$underlying_protocol" -d "$container_ip" --dport "$default_port_number" -j MASQUERADE + + fi + + list_all_protocols+=("$protocol") + list_all_ports+=("$protocol_port") + +done < <(tac "$ADDITIONAL_PROTOCOLS") + +# Space Seperate Lists + +ss_protocols="${list_all_protocols[*]}" +ss_ports="${list_all_ports[*]}" + +echo "$ss_ports" + # Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters -ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$http_port" "$ssh_port" <<'EOF' +ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" "$ss_protocols" "$ss_ports" <<'EOF' set -euo pipefail hostname="$1" container_ip="$2" -http_port="$3" -ssh_port="$4" +ssh_port="$3" +ss_protocols="$4" #convert to valid JSON array +ss_ports="$5" #convert to valid JSON array -jq --arg hn "$hostname" --arg ip "$container_ip" --argjson port "$http_port" --argjson ssh "$ssh_port" \ - '. + {($hn): {ip: $ip, port: $port, ssh: $ssh}}' /etc/nginx/port_map.json > /tmp/port_map.json.new +jq --arg hn "$hostname" \ + --arg ip "$container_ip" \ + --argjson ssh "$ssh_port" \ + --argjson protos "$(printf '%s\n' $ss_protocols | jq -R . | jq -s .)" \ + --argjson ports "$(printf '%s\n' $ss_ports | jq -R . | jq -s 'map(tonumber)')" \ + '. + {($hn): {ip: $ip, ports: ( reduce range(0; $protos | length) as $i ( {ssh: $ssh}; . + { ($protos[$i]): $ports[$i]}))}}' /etc/nginx/port_map.json > /tmp/port_map.json.new mv -f /tmp/port_map.json.new /etc/nginx/port_map.json nginx -s reload EOF echo "✅ Registered $hostname → $container_ip" -echo "🌐 HTTP port: $http_port" echo "🔐 SSH port: $ssh_port" \ No newline at end of file From 55bd06adbea92b2ff85ca9c3f90c133f876cb17f Mon Sep 17 00:00:00 2001 From: maxklema Date: Mon, 23 Jun 2025 15:06:22 -0400 Subject: [PATCH 02/11] Automatic Port Mapping supports multiple Ports, HTTP defaults to 80 --- intern-phxdc-pve1/register-container.sh | 124 ++++++++++++++++-------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/intern-phxdc-pve1/register-container.sh b/intern-phxdc-pve1/register-container.sh index 4b0b6e96..18215119 100644 --- a/intern-phxdc-pve1/register-container.sh +++ b/intern-phxdc-pve1/register-container.sh @@ -3,10 +3,10 @@ set -euo pipefail CTID="$1" -ADDITIONAL_PROTOCOLS="$2" #Optional +ADDITIONAL_PROTOCOLS="${2-}" #set to empty string if not passed if [ -z "$CTID" ]; then - echo "Usage: $0 " + echo "Usage: $0 " exit 1 fi @@ -22,6 +22,7 @@ echo "⏳ Waiting for container to boot and get DHCP lease..." container_ip="" attempts=0 max_attempts=5 + while [[ -z "$container_ip" && $attempts -lt $max_attempts ]]; do container_ip=$(pct exec "$CTID" -- ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d'/' -f1) [[ -z "$container_ip" ]] && sleep 2 && ((attempts++)) @@ -35,6 +36,7 @@ fi hostname=$(pct exec "$CTID" -- hostname) # Check if this container already has a SSH port assigned in PREROUTING + existing_ssh_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:22" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) if [[ -n "$existing_ssh_port" ]]; then @@ -49,7 +51,7 @@ else echo "❌ No available SSH ports found" exit 2 fi -# + # Add PREROUTING rule iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport "$ssh_port" -j DNAT --to-destination "$container_ip:22" @@ -61,71 +63,107 @@ fi # Store all protocols and ports to write to JSON list later. -list_all_protocols=() -list_all_ports=() +if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then -while read line; do + list_all_protocols=() + list_all_ports=() - protocol=$(echo "$line" | awk '{print $1}') - underlying_protocol=$(echo "$line" | awk '{print $2}') - default_port_number=$(echo "$line" | awk '{print $3}') + while read line; do - protocol_port="" - existing_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:$default_port_number" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) + protocol=$(echo "$line" | awk '{print $1}') + underlying_protocol=$(echo "$line" | awk '{print $2}') + default_port_number=$(echo "$line" | awk '{print $3}') - if [[ -n "$existing_port" ]]; then - # Port already exists, so just assign it to protocol_port - echo "ℹ️ This Container already has a $protocol port at $existing_port" - protocol_port="$existing_port" - else - used_protocol_ports=$(iptables -t nat -S PREROUTING | awk -F'--dport ' '/--dport / {print $2}' | awk '{print $1}') - protocol_port=$(comm -23 <(seq 10001 29999 | sort) <(echo "$used_protocol_ports" | sort) | head -n 1 || true) + protocol_port="" + existing_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:$default_port_number" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) - if [[ -z "protocol_port" ]]; then - echo "❌ No available $protocol ports found" - exit 2 - fi + if [[ -n "$existing_port" ]]; then + # Port already exists, so just assign it to protocol_port + echo "ℹ️ This Container already has a $protocol port at $existing_port" + protocol_port="$existing_port" + else + used_protocol_ports=$(iptables -t nat -S PREROUTING | awk -F'--dport ' '/--dport / {print $2}' | awk '{print $1}') + protocol_port=$(comm -23 <(seq 10001 29999 | sort) <(echo "$used_protocol_ports" | sort) | head -n 1 || true) - # Add PREROUTING rule - iptables -t nat -A PREROUTING -i vmbr0 -p "$underlying_protocol" --dport "$protocol_port" -j DNAT --to-destination "$container_ip:$default_port_number" + if [[ -z "protocol_port" ]]; then + echo "❌ No available $protocol ports found" + exit 2 + fi - # Add POSTROUTING rule - iptables -t nat -A POSTROUTING -o vmbr0 -p "$underlying_protocol" -d "$container_ip" --dport "$default_port_number" -j MASQUERADE + # Add PREROUTING rule + iptables -t nat -A PREROUTING -i vmbr0 -p "$underlying_protocol" --dport "$protocol_port" -j DNAT --to-destination "$container_ip:$default_port_number" - fi + # Add POSTROUTING rule + iptables -t nat -A POSTROUTING -o vmbr0 -p "$underlying_protocol" -d "$container_ip" --dport "$default_port_number" -j MASQUERADE - list_all_protocols+=("$protocol") - list_all_ports+=("$protocol_port") + fi -done < <(tac "$ADDITIONAL_PROTOCOLS") + list_all_protocols+=("$protocol") + list_all_ports+=("$protocol_port") -# Space Seperate Lists + done < <(tac "$ADDITIONAL_PROTOCOLS") -ss_protocols="${list_all_protocols[*]}" -ss_ports="${list_all_ports[*]}" + # Space Seperate Lists -echo "$ss_ports" + ss_protocols="$(IFS=, ; echo "${list_all_protocols[*]}")" + ss_ports="$(IFS=, ; echo "${list_all_ports[*]}")" + + #Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters -# Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" "$ss_protocols" "$ss_ports" <<'EOF' set -euo pipefail hostname="$1" container_ip="$2" ssh_port="$3" -ss_protocols="$4" #convert to valid JSON array -ss_ports="$5" #convert to valid JSON array +protos_json=$(echo "$4" | tr ',' '\n' | jq -R . | jq -s .) +ports_json=$(echo "$5" | tr ',' '\n' | jq -R . | jq -s 'map(tonumber)') jq --arg hn "$hostname" \ - --arg ip "$container_ip" \ - --argjson ssh "$ssh_port" \ - --argjson protos "$(printf '%s\n' $ss_protocols | jq -R . | jq -s .)" \ - --argjson ports "$(printf '%s\n' $ss_ports | jq -R . | jq -s 'map(tonumber)')" \ - '. + {($hn): {ip: $ip, ports: ( reduce range(0; $protos | length) as $i ( {ssh: $ssh}; . + { ($protos[$i]): $ports[$i]}))}}' /etc/nginx/port_map.json > /tmp/port_map.json.new + --arg ip "$container_ip" \ + --argjson ssh "$ssh_port" \ + --argjson protos "$protos_json" \ + --argjson ports_list "$ports_json" \ + '. + {($hn): {ip: $ip, ports: ( reduce range(0; $protos | length) as $i ( {ssh: $ssh}; . + { ($protos[$i]): $ports_list[$i]}))}}' /etc/nginx/port_map.json > /tmp/port_map.json.new mv -f /tmp/port_map.json.new /etc/nginx/port_map.json nginx -s reload EOF +else + +# Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters + +ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" <<'EOF' +set -euo pipefail + +hostname="$1" +container_ip="$2" +ssh_port="$3" + +jq --arg hn "$hostname" \ + --arg ip "$container_ip" \ + --argjson ssh "$ssh_port" \ + '. + {($hn): {ip: $ip, ports: {ssh: $ssh}}}' /etc/nginx/port_map.json > /tmp/port_map.json.new + +mv -f /tmp/port_map.json.new /etc/nginx/port_map.json +nginx -s reload +EOF + +fi + +# Results + echo "✅ Registered $hostname → $container_ip" -echo "🔐 SSH port: $ssh_port" \ No newline at end of file +echo "🔐 SSH port: $ssh_port" + +if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then + + for i in "${!list_all_protocols[@]}"; do + echo "📡 ${list_all_protocols[$i]} port: ${list_all_ports[$i]}" + done + +fi + + + From 29237f5d6003d41d9a4c52ccf4bb36f57a910dc8 Mon Sep 17 00:00:00 2001 From: maxklema Date: Mon, 23 Jun 2025 15:09:30 -0400 Subject: [PATCH 03/11] Update dnsmasq.conf --- intern-dnsmasq/dnsmasq.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/intern-dnsmasq/dnsmasq.conf b/intern-dnsmasq/dnsmasq.conf index 889e9892..077d6d34 100644 --- a/intern-dnsmasq/dnsmasq.conf +++ b/intern-dnsmasq/dnsmasq.conf @@ -4,6 +4,7 @@ domain=opensource.mieweb.com interface=eth0 listen-address=127.0.0.1,10.15.0.3 +server=8.8.8.8 # DHCP range dhcp-range=10.15.0.10,10.15.254.254,255.255.0.0,24h From ede90638c65da3fb79771c8c9c6416ceaa53a256 Mon Sep 17 00:00:00 2001 From: maxklema Date: Mon, 23 Jun 2025 17:15:43 -0400 Subject: [PATCH 04/11] dnsmasq and nginx config updates to support opensource.mieweb.org --- intern-dnsmasq/dnsmasq.conf | 4 +++- intern-nginx/reverse_proxy.conf | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/intern-dnsmasq/dnsmasq.conf b/intern-dnsmasq/dnsmasq.conf index 077d6d34..980db907 100644 --- a/intern-dnsmasq/dnsmasq.conf +++ b/intern-dnsmasq/dnsmasq.conf @@ -1,6 +1,7 @@ # /etc/dnsmasq.conf # Domain and interface +domain=opensource.mieweb.org domain=opensource.mieweb.com interface=eth0 listen-address=127.0.0.1,10.15.0.3 @@ -26,6 +27,7 @@ bogus-priv # --- REVERSE PROXY WILDCARD RULE --- # Route all traffic for *.opensource.mieweb.com to the NGINX proxy address=/.opensource.mieweb.com/10.15.20.69 +address=/.opensource.mieweb.org/10.15.20.69 # Dynamic DNS hostname injection -addn-hosts=/etc/dnsmasq.d/hosts +addn-hosts=/etc/dnsmasq.d/hosts \ No newline at end of file diff --git a/intern-nginx/reverse_proxy.conf b/intern-nginx/reverse_proxy.conf index c2757e5f..175bb943 100644 --- a/intern-nginx/reverse_proxy.conf +++ b/intern-nginx/reverse_proxy.conf @@ -18,12 +18,31 @@ server { location / { if ($backend_ip = "") { return 404 "Backend IP not found."; - } + } - proxy_pass http://$backend_ip:80; + proxy_pass http://$backend_ip:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } + +# HTTPS, uncomment when nginx gets private key, will not work w/o it +#server { +# listen 443 ssl; +# server_name .opensource.mieweb.org; +# ssl_certificate /etc/nginx/conf.d/opensource-mieweb-org-chain.pem; +# ssl_certificate_key /etc/nginx/conf.d/opensource-mieweb-org-key.pem; +# location / { +# if ($backend_ip = "") { +# return 404 "Backend IP not found."; +# } + +# proxy_pass http://$backend_ip:80; +# proxy_set_header Host $host; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# proxy_set_header X-Forwarded-Proto $scheme; +# } +#} \ No newline at end of file From cde92e13dd988af199cb1a382d786aba03364f5d Mon Sep 17 00:00:00 2001 From: maxklema Date: Tue, 24 Jun 2025 23:51:59 +0000 Subject: [PATCH 05/11] jump server and container creation scripts --- container-creation/create-lxc-container.sh | 101 ++++++++++++++++++ container-creation/js/authenticateUser.js | 27 +++++ .../js/authenticateUserRunner.js | 8 ++ container-creation/ssh/detectPublicKey.sh | 34 ++++++ .../ssh/publicKeyAppendJumpHost.sh | 13 +++ intern-jump/extract-fingerprint.sh | 27 +++++ 6 files changed, 210 insertions(+) create mode 100644 container-creation/create-lxc-container.sh create mode 100644 container-creation/js/authenticateUser.js create mode 100644 container-creation/js/authenticateUserRunner.js create mode 100755 container-creation/ssh/detectPublicKey.sh create mode 100644 container-creation/ssh/publicKeyAppendJumpHost.sh create mode 100644 intern-jump/extract-fingerprint.sh diff --git a/container-creation/create-lxc-container.sh b/container-creation/create-lxc-container.sh new file mode 100644 index 00000000..b00885c2 --- /dev/null +++ b/container-creation/create-lxc-container.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# Main Container Creation Script +# Modified June 23rd, 2025 by Maxwell Klema +# ------------------------------------------ + +# Authenticate User (Only Valid Users can Create Containers) + +read -p "Enter Proxmox Username → " PROXMOX_USERNAME +read -sp "Enter Proxmox Password → " PROXMOX_PASSWORD +echo "" + +USER_AUTHENTICATED=$(node /root/bin/js/authenticateUserRunner.js authenticateUser "$PROXMOX_USERNAME" "$PROXMOX_PASSWORD") +RETRIES=3 + +while [ $USER_AUTHENTICATED == 'false' ]; do + if [ $RETRIES -gt 0 ]; then + echo "❌ Authentication Failed. Try Again" + read -p "Enter Proxmox Username → " PROXMOX_USERNAME + read -sp "Enter Proxmox Password → " PROXMOX_PASSWORD + echo "" + + USER_AUTHENTICATED=$(node /root/bin/js/authenticateUserRunner.js authenticateUser "$PROXMOX_USERNAME" "$PROXMOX_PASSWORD") + RETRIES=$(($RETRIES-1)) + else + echo "Too many incorrect attempts. Exiting..." + exit 0 + fi +done + +echo "🎉 You have been authenticated" + +# Gather Container Details + +if [ -z "$CONTAINER_NAME" ]; then + read -p "Enter Application Name (One-Word) → " CONTAINER_NAME +fi + +HOST_NAME_EXISTS=$(ssh root@10.15.20.69 "node /etc/nginx/checkHostnameRunner.js checkHostnameExists ${CONTAINER_NAME}") + +while [ $HOST_NAME_EXISTS == 'true' ]; do + echo "Sorry! That name has already been registered. Try another name" + read -p "Enter Application Name (One-Word) → " CONTAINER_NAME + HOST_NAME_EXISTS=$(ssh root@10.15.20.69 "node /etc/nginx/checkHostnameRunner.js checkHostnameExists ${CONTAINER_NAME}") +done + +echo "✅ $CONTAINER_NAME is available" + +if [ -z "$CONTAINER_PASSWORD" ]; then + read -sp "Enter Container Password → " CONTAINER_PASSWORD + echo + read -sp "Confirm Container Password → " CONFIRM_PASSWORD + echo + + while [[ "$CONFIRM_PASSWORD" != "$CONTAINER_PASSWORD" || ${#CONTAINER_PASSWORD} -lt 8 ]]; do + echo "Sorry, try again. Ensure passwords are at least 8 characters." + read -sp "Enter Container Password → " CONTAINER_PASSWORD + echo + read -sp "Confirm Container Password → " CONFIRM_PASSWORD + echo + done +fi + +# Attempt to detect public keys + +echo -e "\n🔑 Attempting to Detect SSH Public Key..." +echo "FP: $SSH_KEY_FP" + +KEY_FILE="/root/bin/ssh/temp_pubs/key.pub" +AUTHORIZED_KEYS="/root/.ssh/authorized_keys" +DETECT_PUBLIC_KEY=$(sudo /root/bin/ssh/detectPublicKey.sh "$SSH_KEY_FP") + +if [ "$DETECT_PUBLIC_KEY" == "Public key found for create-container" ]; then + PUBLIC_KEY_FILE="$KEY_FILE" + echo "🔐 Public Key Found!" +else + echo "🔍 Could not detect Public Key" + + if [ -z "$PUBLIC_KEY" ]; then + read -p "Enter Public Key (Allows Easy Access to Container) [OPTIONAL - LEAVE BLANK TO SKIP] → " PUBLIC_KEY + PUBLIC_KEY_FILE="$KEY_FILE" + + # Check if key is valid + + while [[ "$PUBLIC_KEY" != "" && $(echo "$PUBLIC_KEY" | ssh-keygen -l -f - 2>&1 | tr -d '\r') == "(stdin) is not a public key file." ]]; do + echo "❌ \"$PUBLIC_KEY\" is not a valid key. Enter either a valid key or leave blank to skip." + read -p "Enter Public Key (Allows Easy Access to Container) [OPTIONAL - LEAVE BLANK TO SKIP] → " PUBLIC_KEY + done + + if [ "$PUBLIC_KEY" == "" ]; then + echo "" > "$KEY_FILE" + else + echo "$PUBLIC_KEY" > "$KEY_FILE" + echo "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" && systemctl restart ssh + sudo /root/bin/ssh/publicKeyAppendJumpHost.sh "$(cat $PUBLIC_KEY_FILE)" + fi + + else + echo "$PUBLIC_KEY" > "$KEY_FILE" + echo "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" && systemctl restart ssh + fi +fi \ No newline at end of file diff --git a/container-creation/js/authenticateUser.js b/container-creation/js/authenticateUser.js new file mode 100644 index 00000000..9aa06fd2 --- /dev/null +++ b/container-creation/js/authenticateUser.js @@ -0,0 +1,27 @@ +const axios = require('axios'); +const qs = require('qs'); +const https = require('https'); + +// authenticates user, ensuring they have a valid proxmox account +function authenticateUser(username, password) { + let data = qs.stringify({ + 'username': username + "@pve", + 'password': password + }) + + let config = { + method: 'post', + url: ' https://10.15.0.4:8006/api2/json/access/ticket', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: false // Disable SSL verification for self-signed certificates (Only because public facing domain is resolved to nginx server internally, so have to use hypervisor IP instead of domain) + }), + data: data + }; + + return axios.request(config).then((response) => response.status === 200).catch(() => false); +} + +module.exports = { authenticateUser }; diff --git a/container-creation/js/authenticateUserRunner.js b/container-creation/js/authenticateUserRunner.js new file mode 100644 index 00000000..23a7b680 --- /dev/null +++ b/container-creation/js/authenticateUserRunner.js @@ -0,0 +1,8 @@ +authenticateuser = require("./authenticateUser.js"); + +const [,, func, ...args] = process.argv; +if (func == "authenticateUser") { + authenticateuser.authenticateUser(...args).then((result) => { + console.log(result); + }); +} diff --git a/container-creation/ssh/detectPublicKey.sh b/container-creation/ssh/detectPublicKey.sh new file mode 100755 index 00000000..51572f75 --- /dev/null +++ b/container-creation/ssh/detectPublicKey.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Detect if the user in the current session logged in via an SSH public key +# Last Updated June 17th 2025 Maxwell Klema + +USER="create-container" #Change Later +PUBLIC_KEY_LIST="/root/.ssh/authorized_keys" +TEMP_PUB_FILE="/root/bin/ssh/temp_pubs/key.pub" +# SSH_CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}') + +# Extract latest public key fingerprint based on login from USER + +# LAST_LOGIN=$(journalctl _COMM=sshd | grep "Accepted publickey for $USER from $SSH_CLIENT_IP" | tail -1 ) +# KEY_FINGERPRINT=$(echo $LAST_LOGIN | grep -o 'SHA256[^ ]*') + +KEY_FINGERPRINT="$1" + +if [ KEY_FINGERPRINT != "" ]; then + # Iterate over each public key, compute fingerprint, see if there is a match + + while read line; do + echo "$line" > "$TEMP_PUB_FILE" + PUB_FINGERPRINT=$(ssh-keygen -lf "$TEMP_PUB_FILE" | awk '{print $2}') + if [[ "$PUB_FINGERPRINT" == "$KEY_FINGERPRINT" ]]; then + echo "Public key found for $USER" + exit 0 + fi + done < <(tac $PUBLIC_KEY_LIST) #Iterates backwards without creating subprocess (allows exit in loop) + + echo "" > "$TEMP_PUB_FILE" +fi + +echo "Nothing" + + diff --git a/container-creation/ssh/publicKeyAppendJumpHost.sh b/container-creation/ssh/publicKeyAppendJumpHost.sh new file mode 100644 index 00000000..4f43503b --- /dev/null +++ b/container-creation/ssh/publicKeyAppendJumpHost.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# A script that appends a user's public key to the SSH jump host container to prevent them having to enter a password +# June 24th, 2025 Maxwell Klema + +PUBLIC_KEY=$1 +echo "PUBLIC_KEY: $PUBLIC_KEY" +JUMP_HOST="10.15.0.4" #temporary until jump server ready + +# SSH into the Jump Host + +ssh root@"$JUMP_HOST" "echo '$PUBLIC_KEY' >> /home/jump/.ssh/authorized_keys && systemctl restart ssh" + +exit 0 \ No newline at end of file diff --git a/intern-jump/extract-fingerprint.sh b/intern-jump/extract-fingerprint.sh new file mode 100644 index 00000000..07e47898 --- /dev/null +++ b/intern-jump/extract-fingerprint.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# A script to collect the client's SSH fingerprint and pass that to the container creation container +# Last Modified June 24th, 2025 by Maxwell Klema +# --------------------- + +CURRENT_TIME=$(date +"%B %d %T") + +USER="jump" +SSH_CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}') +RECENT_LOG=$(journalctl _COMM=sshd | grep "Accepted publickey for $USER from $SSH_CLIENT_IP" | tail -1) +LOGGED_TIME=$(echo $RECENT_LOG | awk '{print $3}') + +#check most recent logged time and current time are only max 2 seconds off since multiple users may log in from same IP over time + +epoch1=$(date -d "today $CURRENT_TIME" +%s) +epoch2=$(date -d "today $LOGGED_TIME" +%s) +diff=$((epoch1 - epoch2)) + +KEY_FINGERPRINT="" + +if [ "$diff" -ge 0 ] && [ "$diff" -le 2 ]; then + KEY_FINGERPRINT=$(echo $RECENT_LOG | grep -o 'SHA256[^ ]*') +fi + +echo "KEY FINGERPRINT: $KEY_FINGERPRINT" +export SSH_KEY_FP="$KEY_FINGERPRINT" +ssh -o SendEnv=SSH_KEY_FP -A create-container@10.15.234.122 \ No newline at end of file From ce4cf423fea0465ac78ab8560edbdde717d50c39 Mon Sep 17 00:00:00 2001 From: maxklema Date: Thu, 26 Jun 2025 20:04:41 +0000 Subject: [PATCH 06/11] Container Creation Updates, Nginx Config Updates, other misc. --- container-creation/create-lxc-container.sh | 129 ++++++++++++++---- container-creation/js/authenticateUser.js | 3 + .../js/authenticateUserRunner.js | 5 +- container-creation/ssh/detectPublicKey.sh | 21 ++- .../ssh/publicKeyAppendJumpHost.sh | 7 +- intern-jump/extract-fingerprint.sh | 15 +- intern-nginx/port_map.js | 40 +++++- intern-nginx/reverse_proxy.conf | 78 +++++++---- intern-phxdc-pve1/register-container.sh | 11 +- 9 files changed, 226 insertions(+), 83 deletions(-) diff --git a/container-creation/create-lxc-container.sh b/container-creation/create-lxc-container.sh index b00885c2..450825ce 100644 --- a/container-creation/create-lxc-container.sh +++ b/container-creation/create-lxc-container.sh @@ -5,9 +5,14 @@ # Authenticate User (Only Valid Users can Create Containers) -read -p "Enter Proxmox Username → " PROXMOX_USERNAME -read -sp "Enter Proxmox Password → " PROXMOX_PASSWORD -echo "" +if [ -z "$PROXMOX_USERNAME" ]; then + read -p "Enter Proxmox Username → " PROXMOX_USERNAME +fi + +if [ -z "$PROXMOX_PASSWORD" ]; then + read -sp "Enter Proxmox Password → " PROXMOX_PASSWORD + echo "" +fi USER_AUTHENTICATED=$(node /root/bin/js/authenticateUserRunner.js authenticateUser "$PROXMOX_USERNAME" "$PROXMOX_PASSWORD") RETRIES=3 @@ -27,9 +32,9 @@ while [ $USER_AUTHENTICATED == 'false' ]; do fi done -echo "🎉 You have been authenticated" +echo "🎉 Your proxmox account, $PROXMOX_USERNAME@pve, has been authenticated" -# Gather Container Details +# Gather Container Hostname (hostname.opensource.mieweb.org) if [ -z "$CONTAINER_NAME" ]; then read -p "Enter Application Name (One-Word) → " CONTAINER_NAME @@ -45,6 +50,8 @@ done echo "✅ $CONTAINER_NAME is available" +# Gather Container Password + if [ -z "$CONTAINER_PASSWORD" ]; then read -sp "Enter Container Password → " CONTAINER_PASSWORD echo @@ -58,44 +65,116 @@ if [ -z "$CONTAINER_PASSWORD" ]; then read -sp "Confirm Container Password → " CONFIRM_PASSWORD echo done +else + while [ ${#CONTAINER_PASSWORD} -lt 8 ]; do + echo "Sorry, try again. Ensure passwords are at least 8 characters." + read -sp "Enter Container Password → " CONTAINER_PASSWORD + echo + read -sp "Confirm Container Password → " CONFIRM_PASSWORD + echo + done fi # Attempt to detect public keys echo -e "\n🔑 Attempting to Detect SSH Public Key..." -echo "FP: $SSH_KEY_FP" -KEY_FILE="/root/bin/ssh/temp_pubs/key.pub" AUTHORIZED_KEYS="/root/.ssh/authorized_keys" DETECT_PUBLIC_KEY=$(sudo /root/bin/ssh/detectPublicKey.sh "$SSH_KEY_FP") if [ "$DETECT_PUBLIC_KEY" == "Public key found for create-container" ]; then - PUBLIC_KEY_FILE="$KEY_FILE" echo "🔐 Public Key Found!" else echo "🔍 Could not detect Public Key" if [ -z "$PUBLIC_KEY" ]; then read -p "Enter Public Key (Allows Easy Access to Container) [OPTIONAL - LEAVE BLANK TO SKIP] → " PUBLIC_KEY - PUBLIC_KEY_FILE="$KEY_FILE" - - # Check if key is valid + fi - while [[ "$PUBLIC_KEY" != "" && $(echo "$PUBLIC_KEY" | ssh-keygen -l -f - 2>&1 | tr -d '\r') == "(stdin) is not a public key file." ]]; do - echo "❌ \"$PUBLIC_KEY\" is not a valid key. Enter either a valid key or leave blank to skip." - read -p "Enter Public Key (Allows Easy Access to Container) [OPTIONAL - LEAVE BLANK TO SKIP] → " PUBLIC_KEY - done + # Check if key is valid - if [ "$PUBLIC_KEY" == "" ]; then - echo "" > "$KEY_FILE" - else - echo "$PUBLIC_KEY" > "$KEY_FILE" - echo "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" && systemctl restart ssh - sudo /root/bin/ssh/publicKeyAppendJumpHost.sh "$(cat $PUBLIC_KEY_FILE)" - fi + while [[ "$PUBLIC_KEY" != "" && $(echo "$PUBLIC_KEY" | ssh-keygen -l -f - 2>&1 | tr -d '\r') == "(stdin) is not a public key file." ]]; do + echo "❌ \"$PUBLIC_KEY\" is not a valid key. Enter either a valid key or leave blank to skip." + read -p "Enter Public Key (Allows Easy Access to Container) [OPTIONAL - LEAVE BLANK TO SKIP] → " PUBLIC_KEY + done - else - echo "$PUBLIC_KEY" > "$KEY_FILE" + if [ "$PUBLIC_KEY" != "" ]; then echo "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" && systemctl restart ssh + sudo /root/bin/ssh/publicKeyAppendJumpHost.sh "$PUBLIC_KEY" fi -fi \ No newline at end of file +fi + +# Get HTTP Port Container Listens On + +if [ -z "$HTTP_PORT" ]; then + read -p "Enter HTTP Port for your container to listen on (80-9999) → " HTTP_PORT +fi + +while ! [[ "$HTTP_PORT" =~ ^[0-9]+$ ]] || [ "$HTTP_PORT" -lt 80 ] || [ "$HTTP_PORT" -gt 9999 ]; do + echo "❌ Invalid HTTP Port. It must be a number between 80 and 9,999." + read -p "Enter HTTP Port for your container to listen on (80-9999) → " HTTP_PORT +done + +echo "✅ HTTP Port is set to $HTTP_PORT" + +# Get any other protocols + +protocol_duplicate() { + PROTOCOL="$1" + shift #remaining params are part of list + LIST="$@" + + for item in $LIST; do + if [[ "$item" == "$PROTOCOL" ]]; then + return 0 # Protocol is a duplicate + fi + done + return 1 # Protocol is not a duplicate +} + +read -p "Does your Container require any protocols other than SSH and HTTP? (y/n) → " USE_OTHER_PROTOCOLS +while [ "${USE_OTHER_PROTOCOLS^^}" != "Y" ] && [ "${USE_OTHER_PROTOCOLS^^}" != "N" ]; do + echo "Please answer 'y' for yes or 'n' for no." + read -p "Does your Container require any protocols other than SSH and HTTP? (y/n) → " USE_OTHER_PROTOCOLS +done + +RANDOM_NUM=$(shuf -i 100000-999999 -n 1) +PROTOCOL_FILE="/root/bin/protocols/protocol_list_$RANDOM_NUM.txt" + +if [ "${USE_OTHER_PROTOCOLS^^}" == "Y" ]; then + LIST_PROTOCOLS=() + read -p "Enter the protocol abbreviation (e.g, LDAP for Lightweight Directory Access Protocol). Type \"e\" to exit → " PROTOCOL_NAME + while [ "${PROTOCOL_NAME^^}" != "E" ]; do + FOUND=0 #keep track if protocol was found + while read line; do + PROTOCOL_ABBRV=$(echo "$line" | awk '{print $1}') + protocol_duplicate "$PROTOCOL_ABBRV" "${LIST_PROTOCOLS[@]}" + IS_PROTOCOL_DUPLICATE=$? + if [[ "$PROTOCOL_ABBRV" == "${PROTOCOL_NAME^^}" && "$IS_PROTOCOL_DUPLICATE" -eq 1 ]]; then + LIST_PROTOCOLS+=("$PROTOCOL_ABBRV") + PROTOCOL_UNDRLYING_NAME=$(echo "$line" | awk '{print $3}') + PROTOCOL_DEFAULT_PORT=$(echo "$line" | awk '{print $2}') + echo "$PROTOCOL_ABBRV $PROTOCOL_UNDRLYING_NAME $PROTOCOL_DEFAULT_PORT" >> "$PROTOCOL_FILE" + echo "✅ Protocol ${PROTOCOL_NAME^^} added to container." + FOUND=1 #protocol was found + break + else + echo "❌ Protocol ${PROTOCOL_NAME^^} was already added to your container. Please try again." + FOUND=2 #protocol was a duplicate + break + fi + done < <(cat "/root/bin/protocols/master_protocol_list.txt" | grep "^${PROTOCOL_NAME^^}") + + if [ $FOUND -eq 0 ]; then #if no results found, let user know. + echo "❌ Protocol ${PROTOCOL_NAME^^} not found. Please try again." + fi + + read -p "Enter the protocol abbreviation (e.g, LDAP for Lightweight Directory Access Protocol). Type \"e\" to exit → " PROTOCOL_NAME + done +fi + +# ssh into hypervisor, Cresate the Container, run port mapping script + +rm -rf "$PROTOCOL_FILE" +unset CONFIRM_PASSWORD +unset CONTAINER_PASSWORD \ No newline at end of file diff --git a/container-creation/js/authenticateUser.js b/container-creation/js/authenticateUser.js index 9aa06fd2..61153f1e 100644 --- a/container-creation/js/authenticateUser.js +++ b/container-creation/js/authenticateUser.js @@ -1,3 +1,6 @@ +// Script to authenticate a user into Proxmox +// Last updated June 24th, 2025 by Maxwell Klema + const axios = require('axios'); const qs = require('qs'); const https = require('https'); diff --git a/container-creation/js/authenticateUserRunner.js b/container-creation/js/authenticateUserRunner.js index 23a7b680..5843dd9c 100644 --- a/container-creation/js/authenticateUserRunner.js +++ b/container-creation/js/authenticateUserRunner.js @@ -1,6 +1,9 @@ +// Script to run authenticateUser in the shell +// Last updated June 24th, 2025 by Maxwell Klema + authenticateuser = require("./authenticateUser.js"); -const [,, func, ...args] = process.argv; +const [, , func, ...args] = process.argv; if (func == "authenticateUser") { authenticateuser.authenticateUser(...args).then((result) => { console.log(result); diff --git a/container-creation/ssh/detectPublicKey.sh b/container-creation/ssh/detectPublicKey.sh index 51572f75..cf0f59c2 100755 --- a/container-creation/ssh/detectPublicKey.sh +++ b/container-creation/ssh/detectPublicKey.sh @@ -1,27 +1,26 @@ #!/bin/bash # Detect if the user in the current session logged in via an SSH public key -# Last Updated June 17th 2025 Maxwell Klema +# Last Updated June 25th 2025 Maxwell Klema USER="create-container" #Change Later PUBLIC_KEY_LIST="/root/.ssh/authorized_keys" -TEMP_PUB_FILE="/root/bin/ssh/temp_pubs/key.pub" -# SSH_CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}') -# Extract latest public key fingerprint based on login from USER +RANDOM_NUM=$(shuf -i 100000-999999 -n 1) +TEMP_PUB_FILE="/root/bin/ssh/temp_pubs/key_$RANDOM_NUM.pub" # in case two users are running this script at the same time, they do not overwrite each other's temp files +echo "" > "$TEMP_PUB_FILE" -# LAST_LOGIN=$(journalctl _COMM=sshd | grep "Accepted publickey for $USER from $SSH_CLIENT_IP" | tail -1 ) -# KEY_FINGERPRINT=$(echo $LAST_LOGIN | grep -o 'SHA256[^ ]*') KEY_FINGERPRINT="$1" -if [ KEY_FINGERPRINT != "" ]; then +if [ "$KEY_FINGERPRINT" != "" ]; then # Iterate over each public key, compute fingerprint, see if there is a match - - while read line; do + + while read line; do echo "$line" > "$TEMP_PUB_FILE" PUB_FINGERPRINT=$(ssh-keygen -lf "$TEMP_PUB_FILE" | awk '{print $2}') if [[ "$PUB_FINGERPRINT" == "$KEY_FINGERPRINT" ]]; then echo "Public key found for $USER" + rm -rf "$TEMP_PUB_FILE" exit 0 fi done < <(tac $PUBLIC_KEY_LIST) #Iterates backwards without creating subprocess (allows exit in loop) @@ -29,6 +28,4 @@ if [ KEY_FINGERPRINT != "" ]; then echo "" > "$TEMP_PUB_FILE" fi -echo "Nothing" - - +rm -rf "$TEMP_PUB_FILE" \ No newline at end of file diff --git a/container-creation/ssh/publicKeyAppendJumpHost.sh b/container-creation/ssh/publicKeyAppendJumpHost.sh index 4f43503b..0a92b167 100644 --- a/container-creation/ssh/publicKeyAppendJumpHost.sh +++ b/container-creation/ssh/publicKeyAppendJumpHost.sh @@ -1,13 +1,12 @@ #!/bin/bash # A script that appends a user's public key to the SSH jump host container to prevent them having to enter a password -# June 24th, 2025 Maxwell Klema +# June 25th, 2025 Maxwell Klema PUBLIC_KEY=$1 -echo "PUBLIC_KEY: $PUBLIC_KEY" JUMP_HOST="10.15.0.4" #temporary until jump server ready # SSH into the Jump Host -ssh root@"$JUMP_HOST" "echo '$PUBLIC_KEY' >> /home/jump/.ssh/authorized_keys && systemctl restart ssh" +ssh root@"$JUMP_HOST" "echo '$PUBLIC_KEY' >> /home/create-container/.ssh/authorized_keys && systemctl restart ssh" -exit 0 \ No newline at end of file +exit 0 diff --git a/intern-jump/extract-fingerprint.sh b/intern-jump/extract-fingerprint.sh index 07e47898..42c5e0df 100644 --- a/intern-jump/extract-fingerprint.sh +++ b/intern-jump/extract-fingerprint.sh @@ -1,11 +1,11 @@ #!/bin/bash -# A script to collect the client's SSH fingerprint and pass that to the container creation container +# A script to collect the client's SSH fingerprint and pass that to the content creation container # Last Modified June 24th, 2025 by Maxwell Klema # --------------------- CURRENT_TIME=$(date +"%B %d %T") -USER="jump" +USER="create-container" SSH_CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}') RECENT_LOG=$(journalctl _COMM=sshd | grep "Accepted publickey for $USER from $SSH_CLIENT_IP" | tail -1) LOGGED_TIME=$(echo $RECENT_LOG | awk '{print $3}') @@ -19,9 +19,14 @@ diff=$((epoch1 - epoch2)) KEY_FINGERPRINT="" if [ "$diff" -ge 0 ] && [ "$diff" -le 2 ]; then - KEY_FINGERPRINT=$(echo $RECENT_LOG | grep -o 'SHA256[^ ]*') + KEY_FINGERPRINT=$(echo $RECENT_LOG | grep -o 'SHA256[^ ]*') fi -echo "KEY FINGERPRINT: $KEY_FINGERPRINT" export SSH_KEY_FP="$KEY_FINGERPRINT" -ssh -o SendEnv=SSH_KEY_FP -A create-container@10.15.234.122 \ No newline at end of file +export PROXMOX_USERNAME="$PROXMOX_USERNAME" +export PROXMOX_PASSWORD="$PROXMOX_PASSWORD" +export CONTAINER_NAME="$CONTAINER_NAME" +export CONTAINER_PASSWORD="$CONTAINER_PASSWORD" +export PUBLIC_KEY="$PUBLIC_KEY" + +ssh -o "SendEnv=SSH_KEY_FP PROXMOX_USERNAME PROXMOX_PASSWORD CONTAINER_NAME CONTAINER_PASSWORD PUBLIC_KEY" -A create-container@10.15.234.122 \ No newline at end of file diff --git a/intern-nginx/port_map.js b/intern-nginx/port_map.js index c0c1d5a1..0843a810 100644 --- a/intern-nginx/port_map.js +++ b/intern-nginx/port_map.js @@ -2,10 +2,10 @@ // This is a reverse proxy configuration for Nginx that uses JavaScript to dynamically // map subdomains to specific IP addresses based on a JSON file. // Code is based off of bluehive-testflight's port_map.js -// Last updated: 06-08-2025 Carter Myers +// Last updated: 06-08-2025 Carter Myers \\ 06-25-2025 Maxwell Klema var fs = require('fs'); -var filePath = "/etc/nginx/port_map.json"; +var filePath = "/etc/nginx/port_map.json"; // Make sure Nginx has read access var cachedMapping = null; function loadMapping() { @@ -14,13 +14,14 @@ function loadMapping() { cachedMapping = JSON.parse(content); return true; } catch (e) { + // Optionally log error return false; } } function extractSubdomain(r) { var host = r.variables.host; - var match = host.match(/^([^.]+)\.opensource\.mieweb\.com$/); + var match = host.match(/^([^.]+)\.opensource\.mieweb\.(com|org)$/); if (!match) { r.error("Invalid hostname format: " + host); return null; @@ -28,6 +29,37 @@ function extractSubdomain(r) { return match[1]; } +function httpLookup(r) { + if (cachedMapping === null && !loadMapping()) { + r.error("Failed to load port mapping file."); + r.return(500); + return; + } + + var subdomain = extractSubdomain(r); + if (!subdomain) { + r.return(500); + return; + } + + var entry = cachedMapping[subdomain]; + if (!entry) { + if (!loadMapping()) { + r.error("Reload failed."); + r.return(500); + return; + } + entry = cachedMapping[subdomain]; + if (!entry) { + r.error("No entry found for subdomain: " + subdomain); + r.return(500); + return; + } + } + + return entry.ports.http.toString(); // Always return string +} + function ipLookup(r) { if (cachedMapping === null && !loadMapping()) { r.error("Failed to load port mapping file."); @@ -59,4 +91,4 @@ function ipLookup(r) { return entry.ip; } -export default { ipLookup }; \ No newline at end of file +export default { httpLookup, ipLookup }; \ No newline at end of file diff --git a/intern-nginx/reverse_proxy.conf b/intern-nginx/reverse_proxy.conf index 175bb943..596949d3 100644 --- a/intern-nginx/reverse_proxy.conf +++ b/intern-nginx/reverse_proxy.conf @@ -1,5 +1,6 @@ js_import port_module from /etc/nginx/port_map.js; js_set $backend_ip port_module.ipLookup; +js_set $http_port port_module.httpLookup; # Define a custom log format log_format proxy_log '$remote_addr - $host [$time_local] ' @@ -11,38 +12,65 @@ log_format proxy_log '$remote_addr - $host [$time_local] ' access_log /var/log/nginx/reverse_proxy_access.log proxy_log; error_log /var/log/nginx/reverse_proxy_error.log info; +# HTTPS, uncomment when nginx gets private key, will not work w/o it server { - listen 80; - server_name .opensource.mieweb.com; + listen 443 ssl; + server_name .opensource.mieweb.org; + + ssl_certificate /root/.acme.sh/opensource.mieweb.org/fullchain.cer; + ssl_certificate_key /root/.acme.sh/opensource.mieweb.org/opensource.mieweb.org.key; location / { if ($backend_ip = "") { return 404 "Backend IP not found."; } - proxy_pass http://$backend_ip:80; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + if ($http_port = "") { + return 404 "http port not found."; + } + + proxy_pass http://$backend_ip:$http_port; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; # Use HTTP/1.1 for WebSocket support + proxy_set_header Upgrade $http_upgrade; # Upgrade header for WebSocket support + proxy_set_header Connection "upgrade"; # Connection header for WebSocket support + + # Disable response buffering (important for SSE) + proxy_buffering off; + proxy_cache off; + chunked_transfer_encoding off; + proxy_read_timeout 300s; + } } -# HTTPS, uncomment when nginx gets private key, will not work w/o it -#server { -# listen 443 ssl; -# server_name .opensource.mieweb.org; -# ssl_certificate /etc/nginx/conf.d/opensource-mieweb-org-chain.pem; -# ssl_certificate_key /etc/nginx/conf.d/opensource-mieweb-org-key.pem; -# location / { -# if ($backend_ip = "") { -# return 404 "Backend IP not found."; -# } - -# proxy_pass http://$backend_ip:80; -# proxy_set_header Host $host; -# proxy_set_header X-Real-IP $remote_addr; -# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -# proxy_set_header X-Forwarded-Proto $scheme; -# } -#} \ No newline at end of file +server { + listen 80; + server_name .opensource.mieweb.com; + + location / { + if ($backend_ip = "") { + return 404 "Backend IP not found."; + } + + if ($http_port = "") { + return 404 "http port not found."; + } + + proxy_pass http://$backend_ip:$http_port; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Disable response buffering (important for SSE) + proxy_buffering off; + proxy_cache off; + chunked_transfer_encoding off; + proxy_read_timeout 300s; + + } +} \ No newline at end of file diff --git a/intern-phxdc-pve1/register-container.sh b/intern-phxdc-pve1/register-container.sh index 18215119..8e6fed82 100644 --- a/intern-phxdc-pve1/register-container.sh +++ b/intern-phxdc-pve1/register-container.sh @@ -16,7 +16,7 @@ exec > >(tee -a "$LOGFILE") 2>&1 echo "---- Hookscript started at $(date) ----" echo "⏳ Waiting for container to boot and get DHCP lease..." -#sleep 10 +sleep 10 # Extract IP container_ip="" @@ -40,7 +40,7 @@ hostname=$(pct exec "$CTID" -- hostname) existing_ssh_port=$(iptables -t nat -S PREROUTING | grep "to-destination $container_ip:22" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) if [[ -n "$existing_ssh_port" ]]; then - echo "ℹ️ Container already has SSH port $existing_ssh_port" + echo "ℹ️ Container already has SSH port $existing_ssh_port" ssh_port="$existing_ssh_port" else # Get used SSH ports @@ -154,7 +154,7 @@ fi # Results -echo "✅ Registered $hostname → $container_ip" +echo "✅ Hostname is registered via $hostname → $container_ip" echo "🔐 SSH port: $ssh_port" if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then @@ -163,7 +163,4 @@ if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then echo "📡 ${list_all_protocols[$i]} port: ${list_all_ports[$i]}" done -fi - - - +fi \ No newline at end of file From e0a26f1ca94b3adad7656dd1ef86c77f6dd858a4 Mon Sep 17 00:00:00 2001 From: maxklema Date: Fri, 27 Jun 2025 00:23:41 +0000 Subject: [PATCH 07/11] working on create container script --- container-creation/create-lxc-container | 48 +++++++++++++++++++ ...tainer.sh => get-lxc-container-details.sh} | 15 +++++- container-creation/ssh/detectPublicKey.sh | 12 ++--- 3 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 container-creation/create-lxc-container rename container-creation/{create-lxc-container.sh => get-lxc-container-details.sh} (90%) diff --git a/container-creation/create-lxc-container b/container-creation/create-lxc-container new file mode 100644 index 00000000..4a79fe8f --- /dev/null +++ b/container-creation/create-lxc-container @@ -0,0 +1,48 @@ +#!/bin/bash +# Script to create the pct container, run register container, and migrate container accordingly. +# Last Modified by June 26th, 2025 by Maxwell Klema + +CONTAINER_NAME="$1" +CONTAINER_PASSWORD="$2" +HTTP_PORT="$3" +PROXMOX_USERNAME="$4" +PUB_FILE="$5" +NEXT_ID=$(pvesh get /cluster/nextid) #Get the next available LXC ID + +# Create the Container Clone + +echo "⏳ Cloning Container..." +pct clone 114 $NEXT_ID \ + --hostname $CONTAINER_NAME \ + --full true \ + +# Set Container Options + +echo "⏳ Setting Container Properties.." +pct set $NEXT_ID \ + --tags "TAG" \ + --onboot 1 \ + +pct start $NEXT_ID +pveum aclmod /vms/$NEXT_ID --user "$PROXMOX_USERNAME@pve" --role PVEVMUser +#pct delete $NEXT_ID + +# Get the Container IP Address and install some packages + +echo "⏳ Waiting for DHCP to allocate IP address to container..." +sleep 10 + +CONTAINER_IP=$(pct exec $NEXT_ID -- hostname -I | awk '{print $1}') +pct exec $NEXT_ID -- apt-get upgrade +pct exec $NEXT_ID -- apt install -y sudo +pct exec $NEXT_ID -- apt install -y git +pct exec $NEXT_ID -- touch ~/.ssh/authorized_keys +pct exec $NEXT_ID -- bash -c "cat > ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE + +# Migrate Container (UPDATE WHEN PVE2 has PVE1 PUBLIC KEY) + +#if (( $NEXT_ID % 2 == 0 )); then +# pct migrate $NEXT_ID intern-phxdc-pve2 --target-storage containers-pve2 +#fi + +# Insert User's Public Key into their container \ No newline at end of file diff --git a/container-creation/create-lxc-container.sh b/container-creation/get-lxc-container-details.sh similarity index 90% rename from container-creation/create-lxc-container.sh rename to container-creation/get-lxc-container-details.sh index 450825ce..34ba3498 100644 --- a/container-creation/create-lxc-container.sh +++ b/container-creation/get-lxc-container-details.sh @@ -80,7 +80,11 @@ fi echo -e "\n🔑 Attempting to Detect SSH Public Key..." AUTHORIZED_KEYS="/root/.ssh/authorized_keys" -DETECT_PUBLIC_KEY=$(sudo /root/bin/ssh/detectPublicKey.sh "$SSH_KEY_FP") +RANDOM_NUM=$(shuf -i 100000-999999 -n 1) +PUB_FILE="key_$RANDOM_NUM.pub" +TEMP_PUB_FILE="/root/bin/ssh/temp_pubs/$PUB_FILE" # in case two users are running this script at the same time, they do not overwrite each other's temp files +echo "" > "$TEMP_PUB_FILE" +DETECT_PUBLIC_KEY=$(sudo /root/bin/ssh/detectPublicKey.sh "$SSH_KEY_FP" "$TEMP_PUB_FILE") if [ "$DETECT_PUBLIC_KEY" == "Public key found for create-container" ]; then echo "🔐 Public Key Found!" @@ -100,6 +104,7 @@ else if [ "$PUBLIC_KEY" != "" ]; then echo "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" && systemctl restart ssh + echo "$PUBLIC_KEY" > "$TEMP_PUB_FILE" sudo /root/bin/ssh/publicKeyAppendJumpHost.sh "$PUBLIC_KEY" fi fi @@ -173,8 +178,14 @@ if [ "${USE_OTHER_PROTOCOLS^^}" == "Y" ]; then done fi -# ssh into hypervisor, Cresate the Container, run port mapping script +# send public key file to hypervisor and ssh, Create the Container, run port mapping script +sftp root@10.15.0.4 < "$TEMP_PUB_FILE" - KEY_FINGERPRINT="$1" +TEMP_PUB_FIL="$2" if [ "$KEY_FINGERPRINT" != "" ]; then # Iterate over each public key, compute fingerprint, see if there is a match @@ -20,12 +17,9 @@ if [ "$KEY_FINGERPRINT" != "" ]; then PUB_FINGERPRINT=$(ssh-keygen -lf "$TEMP_PUB_FILE" | awk '{print $2}') if [[ "$PUB_FINGERPRINT" == "$KEY_FINGERPRINT" ]]; then echo "Public key found for $USER" - rm -rf "$TEMP_PUB_FILE" exit 0 fi done < <(tac $PUBLIC_KEY_LIST) #Iterates backwards without creating subprocess (allows exit in loop) echo "" > "$TEMP_PUB_FILE" -fi - -rm -rf "$TEMP_PUB_FILE" \ No newline at end of file +fi \ No newline at end of file From 15f45ebad8f8bcddfd683f6b7ae00785be1f20d7 Mon Sep 17 00:00:00 2001 From: maxklema Date: Fri, 27 Jun 2025 19:21:09 +0000 Subject: [PATCH 08/11] Container Creation Script Changes - migration working --- .../get-lxc-container-details.sh | 13 ++++-- .../create-container.sh | 25 +++++++---- intern-phxdc-pve1/register-container.sh | 42 +++++++++++++------ 3 files changed, 57 insertions(+), 23 deletions(-) rename container-creation/create-lxc-container => intern-phxdc-pve1/create-container.sh (59%) diff --git a/container-creation/get-lxc-container-details.sh b/container-creation/get-lxc-container-details.sh index 34ba3498..ba218825 100644 --- a/container-creation/get-lxc-container-details.sh +++ b/container-creation/get-lxc-container-details.sh @@ -144,7 +144,9 @@ while [ "${USE_OTHER_PROTOCOLS^^}" != "Y" ] && [ "${USE_OTHER_PROTOCOLS^^}" != " done RANDOM_NUM=$(shuf -i 100000-999999 -n 1) -PROTOCOL_FILE="/root/bin/protocols/protocol_list_$RANDOM_NUM.txt" +PROTOCOL_BASE_FILE="protocol_list_$RANDOM_NUM.txt" +PROTOCOL_FILE="/root/bin/protocols/$PROTOCOL_BASE_FILE" +touch "$PROTOCOL_FILE" if [ "${USE_OTHER_PROTOCOLS^^}" == "Y" ]; then LIST_PROTOCOLS=() @@ -178,14 +180,19 @@ if [ "${USE_OTHER_PROTOCOLS^^}" == "Y" ]; then done fi -# send public key file to hypervisor and ssh, Create the Container, run port mapping script +# send public key file & port map file to hypervisor and ssh, Create the Container, run port mapping script sftp root@10.15.0.4 < ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE +rm -rf /var/lib/vz/snippets/container-public-keys/$PUB_FILE -# Migrate Container (UPDATE WHEN PVE2 has PVE1 PUBLIC KEY) +# Set password inside the container -#if (( $NEXT_ID % 2 == 0 )); then -# pct migrate $NEXT_ID intern-phxdc-pve2 --target-storage containers-pve2 -#fi +pct exec $NEXT_ID -- bash -c "echo 'root:$CONTAINER_PASSWORD' | chpasswd" -# Insert User's Public Key into their container \ No newline at end of file +# Run Contianer Provision Script to add container to port_map.json + +/var/lib/vz/snippets/register-container-test.sh $NEXT_ID $HTTP_PORT /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE +rm -rf /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE + +# Migrate to pve2 if Container ID is even + +if (( $NEXT_ID % 2 == 0 )); then + pct stop $NEXT_ID + pct migrate $NEXT_ID intern-phxdc-pve2 --target-storage containers-pve2 --online + ssh root@10.15.0.5 "pct start $NEXT_ID" +fi \ No newline at end of file diff --git a/intern-phxdc-pve1/register-container.sh b/intern-phxdc-pve1/register-container.sh index 8e6fed82..0f65b698 100644 --- a/intern-phxdc-pve1/register-container.sh +++ b/intern-phxdc-pve1/register-container.sh @@ -1,22 +1,26 @@ #!/bin/bash +# var/lib/vz/snippets/register-container.sh +# Script to register a container's IP and ports in the NGINX port map JSON file. +# Last Modified June 27th, 2025 by Maxwell Klema set -euo pipefail -CTID="$1" -ADDITIONAL_PROTOCOLS="${2-}" #set to empty string if not passed - -if [ -z "$CTID" ]; then - echo "Usage: $0 " +if [[ -z "${1-}" || -z "${2-}" ]]; then + echo "Usage: $0 " exit 1 fi +CTID="$1" +http_port="$2" +ADDITIONAL_PROTOCOLS="${3-}" #set to empty string if not passed + # Redirect stdout and stderr to a log file LOGFILE="/var/log/pve-hook-$CTID.log" exec > >(tee -a "$LOGFILE") 2>&1 echo "---- Hookscript started at $(date) ----" echo "⏳ Waiting for container to boot and get DHCP lease..." -sleep 10 +#sleep 10 # Extract IP container_ip="" @@ -110,21 +114,23 @@ if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then #Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters -ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" "$ss_protocols" "$ss_ports" <<'EOF' +ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" "$http_port" "$ss_protocols" "$ss_ports" <<'EOF' set -euo pipefail hostname="$1" container_ip="$2" ssh_port="$3" -protos_json=$(echo "$4" | tr ',' '\n' | jq -R . | jq -s .) -ports_json=$(echo "$5" | tr ',' '\n' | jq -R . | jq -s 'map(tonumber)') +http_port="$4" +protos_json=$(echo "$5" | tr ',' '\n' | jq -R . | jq -s .) +ports_json=$(echo "$6" | tr ',' '\n' | jq -R . | jq -s 'map(tonumber)') jq --arg hn "$hostname" \ --arg ip "$container_ip" \ --argjson ssh "$ssh_port" \ + --argjson http "$http_port" \ --argjson protos "$protos_json" \ --argjson ports_list "$ports_json" \ - '. + {($hn): {ip: $ip, ports: ( reduce range(0; $protos | length) as $i ( {ssh: $ssh}; . + { ($protos[$i]): $ports_list[$i]}))}}' /etc/nginx/port_map.json > /tmp/port_map.json.new + '. + {($hn): {ip: $ip, ports: ( reduce range(0; $protos | length) as $i ( {ssh: $ssh, http: $http}; . + { ($protos[$i]): $ports_list[$i]}))}}' /etc/nginx/port_map.json > /tmp/port_map.json.new mv -f /tmp/port_map.json.new /etc/nginx/port_map.json nginx -s reload @@ -134,17 +140,19 @@ else # Update NGINX port map JSON on the remote host safely using a heredoc and positional parameters -ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" <<'EOF' +ssh root@10.15.20.69 bash -s -- "$hostname" "$container_ip" "$ssh_port" "$http_port" <<'EOF' set -euo pipefail hostname="$1" container_ip="$2" ssh_port="$3" +http_port="$4" jq --arg hn "$hostname" \ --arg ip "$container_ip" \ + --argjson http "$http_port" \ --argjson ssh "$ssh_port" \ - '. + {($hn): {ip: $ip, ports: {ssh: $ssh}}}' /etc/nginx/port_map.json > /tmp/port_map.json.new + '. + {($hn): {ip: $ip, ports: {ssh: $ssh, http: $http}}}' /etc/nginx/port_map.json > /tmp/port_map.json.new mv -f /tmp/port_map.json.new /etc/nginx/port_map.json nginx -s reload @@ -154,8 +162,15 @@ fi # Results +echo "======================================================" +echo "============= COPY THESE PORTS DOWN ==================" +echo "=== Your Container will listen on the protocol's ===" +echo "=== default port, but incoming traffic must go ===" +echo "=== through the ports listed down below ===" +echo "======================================================" echo "✅ Hostname is registered via $hostname → $container_ip" echo "🔐 SSH port: $ssh_port" +echo "🌐 HTTP PORT: $http_port" if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then @@ -163,4 +178,5 @@ if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then echo "📡 ${list_all_protocols[$i]} port: ${list_all_ports[$i]}" done -fi \ No newline at end of file +fi +echo "======================================================" \ No newline at end of file From e9addac2d23282389c24e1a0a35ef5f505d941f6 Mon Sep 17 00:00:00 2001 From: maxklema Date: Sat, 28 Jun 2025 00:25:24 +0000 Subject: [PATCH 09/11] content creation script and related file changes --- .../get-lxc-container-details.sh | 12 ++++- container-creation/ssh/detectPublicKey.sh | 2 +- intern-phxdc-pve1/create-container.sh | 38 ++++++++++++--- intern-phxdc-pve1/register-container.sh | 46 ++++++++++++------- intern-phxdc-pve1/register_proxy_hook.sh | 2 - 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/container-creation/get-lxc-container-details.sh b/container-creation/get-lxc-container-details.sh index ba218825..2de717e1 100644 --- a/container-creation/get-lxc-container-details.sh +++ b/container-creation/get-lxc-container-details.sh @@ -83,7 +83,7 @@ AUTHORIZED_KEYS="/root/.ssh/authorized_keys" RANDOM_NUM=$(shuf -i 100000-999999 -n 1) PUB_FILE="key_$RANDOM_NUM.pub" TEMP_PUB_FILE="/root/bin/ssh/temp_pubs/$PUB_FILE" # in case two users are running this script at the same time, they do not overwrite each other's temp files -echo "" > "$TEMP_PUB_FILE" +touch "$TEMP_PUB_FILE" DETECT_PUBLIC_KEY=$(sudo /root/bin/ssh/detectPublicKey.sh "$SSH_KEY_FP" "$TEMP_PUB_FILE") if [ "$DETECT_PUBLIC_KEY" == "Public key found for create-container" ]; then @@ -181,13 +181,23 @@ if [ "${USE_OTHER_PROTOCOLS^^}" == "Y" ]; then fi # send public key file & port map file to hypervisor and ssh, Create the Container, run port mapping script + +if [ -s $TEMP_PUB_FILE ]; then sftp root@10.15.0.4 < ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE -rm -rf /var/lib/vz/snippets/container-public-keys/$PUB_FILE + +if [ -f "/var/lib/vz/snippets/container-public-keys/$PUBFILE" ]; then + pct exec $NEXT_ID -- touch ~/.ssh/authorized_keys + pct exec $NEXT_ID -- bash -c "cat > ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE + rm -rf /var/lib/vz/snippets/container-public-keys/$PUB_FILE +fi # Set password inside the container @@ -47,8 +50,15 @@ pct exec $NEXT_ID -- bash -c "echo 'root:$CONTAINER_PASSWORD' | chpasswd" # Run Contianer Provision Script to add container to port_map.json -/var/lib/vz/snippets/register-container-test.sh $NEXT_ID $HTTP_PORT /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE -rm -rf /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE +if [ -f "/var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE" ]; then + echo "CONTAINS PROTOCOL FILE" + /var/lib/vz/snippets/register-container-test.sh $NEXT_ID $HTTP_PORT /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE + rm -rf /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE +else + /var/lib/vz/snippets/register-container-test.sh $NEXT_ID $HTTP_PORT +fi + +SSH_PORT=$(iptables -t nat -S PREROUTING | grep "to-destination $CONTAINER_IP:22" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true) # Migrate to pve2 if Container ID is even @@ -56,4 +66,20 @@ if (( $NEXT_ID % 2 == 0 )); then pct stop $NEXT_ID pct migrate $NEXT_ID intern-phxdc-pve2 --target-storage containers-pve2 --online ssh root@10.15.0.5 "pct start $NEXT_ID" -fi \ No newline at end of file +fi + +# Echo Container Details + +# Define friendly, high-contrast colors +BOLD='\033[1m' +BLUE='\033[34m' +MAGENTA='\033[35m' +GREEN='\033[32m' +RESET='\033[0m' + +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +echo -e "📦 ${BLUE}Container ID :${RESET} $NEXT_ID" +echo -e "🌐 ${MAGENTA}Internal IP :${RESET} $CONTAINER_IP" +echo -e "🔗 ${GREEN}Domain Name :${RESET} https://$CONTAINER_NAME.opensource.mieweb.org" +echo -e "🛠️ ${BLUE}SSH Access :${RESET} ssh -p $SSH_PORT root@$CONTAINER_NAME.opensource.mieweb.org" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" \ No newline at end of file diff --git a/intern-phxdc-pve1/register-container.sh b/intern-phxdc-pve1/register-container.sh index 0f65b698..83a3cdd4 100644 --- a/intern-phxdc-pve1/register-container.sh +++ b/intern-phxdc-pve1/register-container.sh @@ -1,7 +1,7 @@ #!/bin/bash # var/lib/vz/snippets/register-container.sh # Script to register a container's IP and ports in the NGINX port map JSON file. -# Last Modified June 27th, 2025 by Maxwell Klema +# Last Modified June 27 2025 by Maxwell Klema set -euo pipefail @@ -162,21 +162,33 @@ fi # Results -echo "======================================================" -echo "============= COPY THESE PORTS DOWN ==================" -echo "=== Your Container will listen on the protocol's ===" -echo "=== default port, but incoming traffic must go ===" -echo "=== through the ports listed down below ===" -echo "======================================================" -echo "✅ Hostname is registered via $hostname → $container_ip" -echo "🔐 SSH port: $ssh_port" -echo "🌐 HTTP PORT: $http_port" - +# Define high-contrast colors +BOLD='\033[1m' +BLUE='\033[34m' +MAGENTA='\033[35m' +GREEN='\033[32m' +CYAN='\033[36m' +RESET='\033[0m' + +# Top border and title +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +echo -e "${BOLD}🔔 ${MAGENTA}COPY THESE PORTS DOWN${RESET} — ${CYAN}For External Access${RESET}" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +echo -e "📌 ${BLUE}Note:${RESET} Your container listens on default ports internally," +echo -e " but EXTERNAL traffic must use the ports listed below:" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" + +# Port info +echo -e "✅ ${GREEN}Hostname Registration:${RESET} $hostname → $container_ip" +echo -e "🔐 ${MAGENTA}SSH Port :${RESET} $ssh_port" +echo -e "🌐 ${BLUE}HTTP Port :${RESET} $http_port" + +# Additional protocols (if any) if [ ! -z "$ADDITIONAL_PROTOCOLS" ]; then - - for i in "${!list_all_protocols[@]}"; do - echo "📡 ${list_all_protocols[$i]} port: ${list_all_ports[$i]}" - done - + for i in "${!list_all_protocols[@]}"; do + echo -e "📡 ${CYAN}${list_all_protocols[$i]} Port :${RESET} ${list_all_ports[$i]}" + done fi -echo "======================================================" \ No newline at end of file + +# Bottom border +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" \ No newline at end of file diff --git a/intern-phxdc-pve1/register_proxy_hook.sh b/intern-phxdc-pve1/register_proxy_hook.sh index 91da08dc..a4ade333 100644 --- a/intern-phxdc-pve1/register_proxy_hook.sh +++ b/intern-phxdc-pve1/register_proxy_hook.sh @@ -1,8 +1,6 @@ #!/bin/bash - # /var/lib/vz/snippets/register_proxy_hook.sh -set -x # Enable debug output echo "DEBUG: Hook script /var/lib/vz/snippets/register_proxy_hook.sh started. Event: $2, CTID: $1" >> /tmp/hook_debug.log # Hook script for container events From 01f04008e1552819ad27dd55097b0a5f57f34d43 Mon Sep 17 00:00:00 2001 From: maxklema Date: Mon, 30 Jun 2025 16:17:53 +0000 Subject: [PATCH 10/11] Bug Fixes --- .../create-container.sh | 5 ++--- .../get-lxc-container-details.sh | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) rename {intern-phxdc-pve1 => container-creation}/create-container.sh (91%) diff --git a/intern-phxdc-pve1/create-container.sh b/container-creation/create-container.sh similarity index 91% rename from intern-phxdc-pve1/create-container.sh rename to container-creation/create-container.sh index 58ab3274..f2be1cc6 100644 --- a/intern-phxdc-pve1/create-container.sh +++ b/container-creation/create-container.sh @@ -1,6 +1,6 @@ #!/bin/bash # Script to create the pct container, run register container, and migrate container accordingly. -# Last Modified by June 27th, 2025 by Maxwell Klema +# Last Modified by June 30th, 2025 by Maxwell Klema CONTAINER_NAME="$1" CONTAINER_PASSWORD="$2" @@ -38,7 +38,7 @@ pct exec $NEXT_ID -- apt-get upgrade pct exec $NEXT_ID -- apt install -y sudo pct exec $NEXT_ID -- apt install -y git -if [ -f "/var/lib/vz/snippets/container-public-keys/$PUBFILE" ]; then +if [ -f "/var/lib/vz/snippets/container-public-keys/$PUB_FILE" ]; then pct exec $NEXT_ID -- touch ~/.ssh/authorized_keys pct exec $NEXT_ID -- bash -c "cat > ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE rm -rf /var/lib/vz/snippets/container-public-keys/$PUB_FILE @@ -77,7 +77,6 @@ MAGENTA='\033[35m' GREEN='\033[32m' RESET='\033[0m' -echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" echo -e "📦 ${BLUE}Container ID :${RESET} $NEXT_ID" echo -e "🌐 ${MAGENTA}Internal IP :${RESET} $CONTAINER_IP" echo -e "🔗 ${GREEN}Domain Name :${RESET} https://$CONTAINER_NAME.opensource.mieweb.org" diff --git a/container-creation/get-lxc-container-details.sh b/container-creation/get-lxc-container-details.sh index 2de717e1..d56d906e 100644 --- a/container-creation/get-lxc-container-details.sh +++ b/container-creation/get-lxc-container-details.sh @@ -3,6 +3,15 @@ # Modified June 23rd, 2025 by Maxwell Klema # ------------------------------------------ +# Define color variables (works on both light and dark backgrounds) +RESET="\033[0m" +BOLD="\033[1m" +MAGENTA='\033[35m' + +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +echo -e "${BOLD}${MAGENTA}📦 MIE Container Creation Script ${RESET}" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" + # Authenticate User (Only Valid Users can Create Containers) if [ -z "$PROXMOX_USERNAME" ]; then @@ -195,9 +204,9 @@ put $PROTOCOL_FILE /var/lib/vz/snippets/container-port-maps/ EOF fi -echo -e "\n====================================" -echo "🚀 Starting Container Creation..." -echo -e "====================================\n" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +echo -e "${BOLD}${MAGENTA}🚀 Starting Container Creation...${RESET}" +echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" ssh root@10.15.0.4 "/var/lib/vz/snippets/create-container.sh $CONTAINER_NAME $CONTAINER_PASSWORD $HTTP_PORT $PROXMOX_USERNAME $PUB_FILE $PROTOCOL_BASE_FILE" @@ -205,4 +214,5 @@ rm -rf "$PROTOCOL_FILE" rm -rf "$TEMP_PUB_FILE" unset CONFIRM_PASSWORD -unset CONTAINER_PASSWORD \ No newline at end of file +unset CONTAINER_PASSWORD +unset PUBLIC_KEY \ No newline at end of file From 6a9fda0b98d4540baa52d161208f3b8cb7fa5076 Mon Sep 17 00:00:00 2001 From: maxklema Date: Mon, 30 Jun 2025 20:26:00 +0000 Subject: [PATCH 11/11] container lock (disk) error fixed and cleanup tasks --- container-creation/create-container.sh | 24 ++++++++++++++++++- .../get-lxc-container-details.sh | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/container-creation/create-container.sh b/container-creation/create-container.sh index f2be1cc6..583be02a 100644 --- a/container-creation/create-container.sh +++ b/container-creation/create-container.sh @@ -2,6 +2,8 @@ # Script to create the pct container, run register container, and migrate container accordingly. # Last Modified by June 30th, 2025 by Maxwell Klema +trap cleanup SIGINT SIGTERM SIGHUP + CONTAINER_NAME="$1" CONTAINER_PASSWORD="$2" HTTP_PORT="$3" @@ -10,6 +12,27 @@ PUB_FILE="$5" PROTOCOL_FILE="$6" NEXT_ID=$(pvesh get /cluster/nextid) #Get the next available LXC ID +# Run cleanup commands in case script is interrupted + +function cleanup() +{ + BOLD='\033[1m' + RESET='\033[0m' + + echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" + echo "⚠️ Script was abruptly exited. Running cleanup tasks." + echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" + pct unlock 114 + if [ -f "/var/lib/vz/snippets/container-public-keys/$PUB_FILE" ]; then + rm -rf /var/lib/vz/snippets/container-public-keys/$PUB_FILE + fi + if [ -f "/var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE" ]; then + rm -rf /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE + fi + exit 1 +} + + # Create the Container Clone echo "⏳ Cloning Container..." @@ -37,7 +60,6 @@ CONTAINER_IP=$(pct exec $NEXT_ID -- hostname -I | awk '{print $1}') pct exec $NEXT_ID -- apt-get upgrade pct exec $NEXT_ID -- apt install -y sudo pct exec $NEXT_ID -- apt install -y git - if [ -f "/var/lib/vz/snippets/container-public-keys/$PUB_FILE" ]; then pct exec $NEXT_ID -- touch ~/.ssh/authorized_keys pct exec $NEXT_ID -- bash -c "cat > ~/.ssh/authorized_keys"< /var/lib/vz/snippets/container-public-keys/$PUB_FILE diff --git a/container-creation/get-lxc-container-details.sh b/container-creation/get-lxc-container-details.sh index d56d906e..9715de8c 100644 --- a/container-creation/get-lxc-container-details.sh +++ b/container-creation/get-lxc-container-details.sh @@ -208,7 +208,7 @@ echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━ echo -e "${BOLD}${MAGENTA}🚀 Starting Container Creation...${RESET}" echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" -ssh root@10.15.0.4 "/var/lib/vz/snippets/create-container.sh $CONTAINER_NAME $CONTAINER_PASSWORD $HTTP_PORT $PROXMOX_USERNAME $PUB_FILE $PROTOCOL_BASE_FILE" +ssh -t root@10.15.0.4 "/var/lib/vz/snippets/create-container.sh $CONTAINER_NAME $CONTAINER_PASSWORD $HTTP_PORT $PROXMOX_USERNAME $PUB_FILE $PROTOCOL_BASE_FILE" rm -rf "$PROTOCOL_FILE" rm -rf "$TEMP_PUB_FILE"