#!/bin/bash # shellcheck disable=SC2086,SC2046,SC2155 # # nginx-controller - https://phus.lu/code/register-nginx-conf.bash # # @reboot root nohup /bin/bash /home/phuslu/web/code/register-nginx-conf.bash /dev/null & # # Copyright (c) 2024 Phus Lu # # Authors: Phus Lu # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # pidtree() ( # https://superuser.com/a/784102/114255 [ -n "$ZSH_VERSION" ] && setopt shwordsplit declare -A childs while read pid ppid; do childs[$ppid]+=" $pid" done < <(ps -e -o pid= -o ppid=) walk() { for i in ${childs[$1]}; do walk $i done echo $1 } for i in "$@";do walk $i done ) generate_nginx_conf () { local cid=$1 local name=$2 local ipaddr=$3 local port=$4 local domain=$5 echo "# generated by $0 # registered for ${cid} upstream ${name}.internal { server ${ipaddr}:${port}; }" if [ "${domain}" != "" ]; then echo " server { listen 80; server_name ${domain}; location / { proxy_pass http://${name}.internal; proxy_http_version 1.1; proxy_set_header Host \$http_host; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection Upgrade; proxy_read_timeout 180; proxy_connect_timeout 180; proxy_send_timeout 180; send_timeout 180; } }" fi } update_nginx_conf () { local ns=$1 local cid=$2 local pid=$3 if [[ $(ctr -n ${ns} container info ${cid}) =~ (\.|\/|host)name\":\ \"/?([a-z0-9\.\-_]+)\", ]]; then local name=${BASH_REMATCH[2]} else return fi if [[ $(nsenter -t ${pid} -n ip -o -4 a) =~ [0-9]+:\ e[a-z0-9]+\ +inet\ ([0-9\.]+) ]]; then local ipaddr=${BASH_REMATCH[1]} fi local environ=$(cat -A /proc/${pid}/environ) if [[ ${environ} =~ @PORT=([0-9]+) ]]; then local port=${BASH_REMATCH[1]} fi if [[ ${environ} =~ @DOMAIN=([^\^]+) ]]; then local domain=${BASH_REMATCH[1]} fi if [ "${port}" == "0" ]; then for i in 0 1 2 3 5 5 5 5 5 5; do sleep ${i} local lines=$(nsenter -t ${pid} -n ss -antl) local pattens=('(0.0.0.0|\*|10.+):(80)(?= )' '(0.0.0.0|\*|10.+):([0-9]+)') for regex in "${pattens[@]}"; do if [[ $lines =~ $regex ]]; then local port=${BASH_REMATCH[2]} break 2 fi done done fi if [ "${port}" == "0" -o "${port}" == "" ]; then return fi generate_nginx_conf "${cid}" "${name}" "${ipaddr}" "${port}" "${domain}" >/etc/nginx/sites-enabled/${name}.internal if nginx -t; then nginx -s reload fi } remove_nginx_conf () { local ns=$1 local cid=$2 rm -f $(grep -l "^# registered for ${cid}" /etc/nginx/sites-enabled/*.internal) if nginx -t; then nginx -s reload fi } list_watch () { ctr namespace ls -q | while read -r ns; do ctr -n ${ns} task ls | while read -r cid pid status; do if [ "$status" != "RUNNING" ]; then continue fi update_nginx_conf ${ns} ${cid} ${pid} done done ctr events | while read -r line; do if [[ $line =~ \ ([a-z0-9\.\-_]+)\ /tasks/start\ \{\"container_id\":\"([0-9a-f]+)\",\"pid\":([0-9]+) ]]; then update_nginx_conf "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" elif [[ $line =~ \ ([a-z0-9\.\-_]+)\ /tasks/delete\ \{\"container_id\":\"([0-9a-f]+)\" ]]; then remove_nginx_conf "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" fi done } trap 'kill $(pidtree $$)' EXIT list_watch