acme: add support for nginx webserver
authorAnsuel Smith <redacted>
Wed, 18 Jul 2018 01:02:11 +0000 (03:02 +0200)
committerToke Høiland-Jørgensen <redacted>
Wed, 19 Sep 2018 14:21:00 +0000 (16:21 +0200)
This adds a metapakcge for acme luci ap without uhttpd dependency and adds entities and check to stop handle nginx server and modify the certificate set automatically.

Signed-off-by: Ansuel Smith <redacted>
net/acme/Makefile
net/acme/files/acme-cbi.lua
net/acme/files/acme.config
net/acme/files/run.sh

index f787f54ebecbfcc4c097abda0c86700c18930b11..42d1026da6ec9cb657d598cf4058ef45df7c720a 100644 (file)
@@ -75,7 +75,7 @@ define Package/luci-app-acme
   SECTION:=luci
   CATEGORY:=LuCI
   TITLE:=ACME package - LuCI interface
-  DEPENDS:= lua luci-base +acme luci-app-uhttpd
+  DEPENDS:= lua luci-base +acme 
   SUBMENU:=3. Applications
 endef
 
index 193699cc398ac3e475118cb8155a8c1d5ddfccf9..5c483491e43badadab0895a5cf9f25208a48f970 100644 (file)
@@ -10,6 +10,12 @@ Copyright 2016 Toke Høiland-Jørgensen <toke@toke.dk>
 
 ]]--
 
+local ipkg = require "luci.model.ipkg"
+
+local nginx_presence = ipkg.installed("nginx-all-module") or ipkg.installed("nginx-ssl") or false
+
+local uhttpd_presence = ipkg.installed("uhttpd") or false
+
 m = Map("acme", translate("ACME certificates"),
        translate("This configures ACME (Letsencrypt) automatic certificate installation. " ..
                   "Simply fill out this to have the router configured with Letsencrypt-issued " ..
@@ -52,10 +58,21 @@ kl = cs:option(Value, "keylength", translate("Key length"),
 kl.rmempty = false
 kl.datatype = "and(uinteger,min(2048))"
 
+if uhttpd_presence then
 u = cs:option(Flag, "update_uhttpd", translate("Use for uhttpd"),
               translate("Update the uhttpd config with this certificate once issued " ..
-                        "(only select this for one certificate)."))
+                        "(only select this for one certificate)." .. 
+                        "Is also available luci-app-uhttpd to configure uhttpd form the LuCI interface."))
+u.rmempty = false
+end
+
+if nginx_presence then
+u = cs:option(Flag, "update_nginx", translate("Use for nginx"),
+              translate("Update the nginx config with this certificate once issued " ..
+                        "(only select this for one certificate)." .. 
+                        "Nginx must support ssl, if not it won't start as it needs to be compiled with ssl support to use cert options"))
 u.rmempty = false
+end
 
 wr = cs:option(Value, "webroot", translate("Webroot directory"),
                translate("Webserver root directory. Set this to the webserver " ..
index af12ce1fb008e2f2f2f37e4dd1ae389569e7f3ab..95565c83281fbea0b037dd65206904d592e8f534 100644 (file)
@@ -8,5 +8,6 @@ config cert 'example'
        option use_staging 1
        option keylength 2048
        option update_uhttpd 1
+       option update_nginx 1
        option webroot ""
        list domains example.org
index 25c36028a81138950332b811e1a7305f487a93a2..506c19a63259b9546466ae603f99d220bd425c12 100644 (file)
@@ -17,6 +17,9 @@ UHTTPD_LISTEN_HTTP=
 STATE_DIR='/etc/acme'
 ACCOUNT_EMAIL=
 DEBUG=0
+NGINX_WEBSERVER=0
+UPDATE_NGINX=0
+UPDATE_UHTTPD=0
 
 . /lib/functions.sh
 
@@ -42,9 +45,13 @@ debug()
     [ "$DEBUG" -eq "1" ] && logger -t acme -s -p daemon.debug "$@"
 }
 
-get_listeners()
-{
-    netstat -nptl 2>/dev/null | awk 'match($4, /:80$/){split($7, parts, "/"); print parts[2];}' | uniq | tr "\n" " "
+get_listeners() {
+    local proto rq sq listen remote state program
+    netstat -nptl 2>/dev/null | while read proto rq sq listen remote state program; do
+        case "$proto#$listen#$program" in
+            tcp#*:80#[0-9]*/*) echo -n "${program%% *} " ;;
+        esac
+    done
 }
 
 pre_checks()
@@ -54,37 +61,58 @@ pre_checks()
     log "Running pre checks for $main_domain."
 
     listeners="$(get_listeners)"
-    debug "port80 listens: $listeners"
-
-    case "$listeners" in
-        "uhttpd")
-            debug "Found uhttpd listening on port 80; trying to disable."
-
-            UHTTPD_LISTEN_HTTP=$(uci get uhttpd.main.listen_http)
 
-            if [ -z "$UHTTPD_LISTEN_HTTP" ]; then
-                err "$main_domain: Unable to find uhttpd listen config."
-                err "Manually disable uhttpd or set webroot to continue."
-                return 1
-            fi
+    debug "port80 listens: $listeners"
 
-            uci set uhttpd.main.listen_http=''
-            uci commit uhttpd || return 1
-            if ! /etc/init.d/uhttpd reload ; then
-                uci set uhttpd.main.listen_http="$UHTTPD_LISTEN_HTTP"
-                uci commit uhttpd
-                return 1
-            fi
+    for listener in $(get_listeners); do
+        pid="${listener%/*}"
+        cmd="${listener#*/}"
+        
+        case "$cmd" in
+            uhttpd)
+                debug "Found uhttpd listening on port 80; trying to disable."
+    
+                UHTTPD_LISTEN_HTTP=$(uci get uhttpd.main.listen_http)
+    
+                if [ -z "$UHTTPD_LISTEN_HTTP" ]; then
+                    err "$main_domain: Unable to find uhttpd listen config."
+                    err "Manually disable uhttpd or set webroot to continue."
+                    return 1
+                fi
+    
+                uci set uhttpd.main.listen_http=''
+                uci commit uhttpd || return 1
+                if ! /etc/init.d/uhttpd reload ; then
+                    uci set uhttpd.main.listen_http="$UHTTPD_LISTEN_HTTP"
+                    uci commit uhttpd
+                    return 1
+                fi
             ;;
-        "")
-            debug "Nothing listening on port 80."
+            nginx*)
+                debug "Found nginx listening on port 80; trying to disable."
+                NGINX_WEBSERVER=1
+                local tries=0
+                while grep -sq "$cmd" "/proc/$pid/cmdline" && kill -0 "$pid"; do
+                /etc/init.d/nginx stop
+                    if [ $tries -gt 10 ]; then
+                        debug "Can't stop nginx. Terminating script."
+                        return 1
+                    fi
+                    debug "Waiting for nginx to stop..."
+                    tries=$tries+1
+                    sleep 1
+                done
             ;;
-        *)
-            err "$main_domain: Cannot run in standalone mode; another daemon is listening on port 80."
-            err "Disable other daemon or set webroot to continue."
-            return 1
+            "")
+                debug "Nothing listening on port 80."
             ;;
-    esac
+            *)
+                err "$main_domain: Cannot run in standalone mode; another daemon is listening on port 80."
+                err "Disable other daemon or set webroot to continue."
+                return 1
+            ;;
+        esac
+    done
 
     iptables -I input_rule -p tcp --dport 80 -j ACCEPT -m comment --comment "ACME" || return 1
     ip6tables -I input_rule -p tcp --dport 80 -j ACCEPT -m comment --comment "ACME" || return 1
@@ -101,11 +129,18 @@ post_checks()
     iptables -D input_rule -p tcp --dport 80 -j ACCEPT -m comment --comment "ACME" 2>/dev/null
     ip6tables -D input_rule -p tcp --dport 80 -j ACCEPT -m comment --comment "ACME" 2>/dev/null
 
-    if [ -e /etc/init.d/uhttpd ] && [ -n "$UHTTPD_LISTEN_HTTP" ]; then
-        uci set uhttpd.main.listen_http="$UHTTPD_LISTEN_HTTP"
-        uci commit uhttpd
+    if [ -e /etc/init.d/uhttpd ] && ( [ -n "$UHTTPD_LISTEN_HTTP" ] || [ $UPDATE_UHTTPD -eq 1 ] ); then
+        if [ -n "$UHTTPD_LISTEN_HTTP" ]; then
+            uci set uhttpd.main.listen_http="$UHTTPD_LISTEN_HTTP"
+            uci commit uhttpd
+            UHTTPD_LISTEN_HTTP=
+        fi
         /etc/init.d/uhttpd reload
-        UHTTPD_LISTEN_HTTP=
+    fi
+
+    if [ -e /etc/init.d/nginx ] && ( [ "$NGINX_WEBSERVER" -eq 1 ] || [ $UPDATE_NGINX -eq 1 ] ); then
+        NGINX_WEBSERVER=0
+        /etc/init.d/nginx restart
     fi
 }
 
@@ -137,6 +172,7 @@ issue_cert()
     local enabled
     local use_staging
     local update_uhttpd
+    local update_nginx
     local keylength
     local domains
     local main_domain
@@ -148,10 +184,14 @@ issue_cert()
     config_get_bool enabled "$section" enabled 0
     config_get_bool use_staging "$section" use_staging
     config_get_bool update_uhttpd "$section" update_uhttpd
+    config_get_bool update_nginx "$section" update_nginx
     config_get domains "$section" domains
     config_get keylength "$section" keylength
     config_get webroot "$section" webroot
     config_get dns "$section" dns
+    
+    UPDATE_NGINX=$update_nginx
+    UPDATE_UHTTPD=$update_uhttpd
 
     [ "$enabled" -eq "1" ] || return
 
@@ -215,12 +255,18 @@ issue_cert()
         return 1
     fi
 
-    if [ "$update_uhttpd" -eq "1" ]; then
+    if [ -e /etc/init.d/uhttpd ] && [ "$update_uhttpd" -eq "1" ]; then
         uci set uhttpd.main.key="$STATE_DIR/${main_domain}/${main_domain}.key"
         uci set uhttpd.main.cert="$STATE_DIR/${main_domain}/fullchain.cer"
         # commit and reload is in post_checks
     fi
 
+    if [ -e /etc/init.d/nginx ] && [ "$update_nginx" -eq "1" ]; then
+        sed -i "s#ssl_certificate\ .*#ssl_certificate $STATE_DIR/${main_domain}/fullchain.cer;#g" /etc/nginx/nginx.conf
+        sed -i "s#ssl_certificate_key\ .*#ssl_certificate_key $STATE_DIR/${main_domain}/${main_domain}.key;#g" /etc/nginx/nginx.conf
+        # commit and reload is in post_checks
+    fi
+
     post_checks
 }
 
git clone https://git.99rst.org/PROJECT