├── install.sh ├── README.md └── renew.acme.sh /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p /config/.acme.sh /config/scripts 4 | curl -o /config/.acme.sh/acme.sh https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh 5 | curl -o /config/scripts/renew.acme.sh https://raw.githubusercontent.com/j-c-m/ubnt-letsencrypt/master/renew.acme.sh 6 | chmod 755 /config/.acme.sh/acme.sh /config/scripts/renew.acme.sh 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Let's Encrypt with the Ubiquiti EdgeRouter 2 | 3 | This guide uses and 4 | to generate a valid SSL certificate for the EdgeRouter. 5 | 6 | * Does not ever expose the admin GUI to the internet 7 | * 100% /config driven, does not require modification to EdgeOS system files 8 | 9 | ## Install acme.sh & scripts 10 | 11 | * Connect via ssh to your EdgeRouter and execute the following command. 12 | ``` 13 | curl https://raw.githubusercontent.com/zen/ubnt-letsencrypt/master/install.sh | sudo bash 14 | ``` 15 | 16 | ## Configuration 17 | 18 | * In the steps below replace/verify the following: 19 | * subdomain.example.com - FQDN 20 | * 192.168.1.1 - LAN IP of Router 21 | * Configure DNS record for subdomain.example.com to your public WAN IP. 22 | * Connect via ssh to your EdgeRouter. 23 | 24 | 1. Initialize your certificate. 25 | 26 | ``` 27 | sudo /config/scripts/renew.acme.sh -d subdomain.example.com 28 | ``` 29 | 30 | You can include additional common names for your certificate, so long as they resolve to the same WAN address: 31 | 32 | ``` 33 | sudo /config/scripts/renew.acme.sh -d subdomain.example.com -d subdomain2.example.com 34 | ``` 35 | 36 | 2. Enter configuration mode. 37 | 38 | ``` 39 | configure 40 | ``` 41 | 42 | 3. Setup static host mapping for FQDN to the LAN IP. 43 | 44 | ``` 45 | set system static-host-mapping host-name subdomain.example.com inet 192.168.1.1 46 | ``` 47 | 48 | 4. Configure cert-file location for gui. 49 | 50 | ``` 51 | set service gui cert-file /config/ssl/server.pem 52 | set service gui ca-file /config/ssl/ca.pem 53 | ``` 54 | 55 | 5. Configure task scheduler to renew certificate automatically. 56 | 57 | ``` 58 | set system task-scheduler task renew.acme executable path /config/scripts/renew.acme.sh 59 | set system task-scheduler task renew.acme interval 1d 60 | set system task-scheduler task renew.acme executable arguments '-d subdomain.example.com' 61 | ``` 62 | 63 | If you included multiple names in step 1, you'll need to include any additional names here as well. 64 | 65 | ``` 66 | set system task-scheduler task renew.acme executable arguments '-d subdomain.example.com -d subdomain2.example.com' 67 | ``` 68 | 69 | 6. Commit, save and exit configuration mode. 70 | 71 | ``` 72 | commit 73 | save 74 | exit 75 | ``` 76 | 77 | 78 | 7. Accesss your router by going to 79 | 80 | ## Changelog 81 | 82 | 20220624 - Update acme.sh repo to https://github.com/acmesh-official/acme.sh 83 | 20210622 - Update option handling to pass --debug and --force to acme.sh 84 | 20210621 - Default to Let's Encrypt CA 85 | - Add -f to force renew 86 | 20200419 - Use SIGTERM for GUI service stop 87 | 20200109 - Use systemctl on 2.0 to start GUI service 88 | 20191022 - Prevent sudo error 89 | 20190311 - Initialize certificate first outside of configuration mode 90 | 20180609 - Install script 91 | 20180605 - IPv6 support 92 | 20180213 - Deprecate -i option 93 | 20171126 - Add ca.pem for complete certificate chain 94 | - Temporarily disable http port forwarding during renew 95 | 20171013 - Remove reload.acme.sh 96 | 20170530 - Check wan ip 97 | 20170417 - Stop gui service during challenge 98 | 20170320 - Add multiple name support 99 | 20170317 - Change from standalone to webroot auth using lighttpd 100 | 20170224 - Bug fixes 101 | 20170110 - Born 102 | -------------------------------------------------------------------------------- /renew.acme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | echo "Usage: $0 -d [-d ] [options ...] 5 | Options: 6 | -h, --help Show this help message. 7 | -d, --domain Specifies domain for cert, allowed multiple times. 8 | -f, --force Force cert renewal. 9 | --debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted. 10 | " 1>&2; exit 1; 11 | } 12 | 13 | kill_and_wait() { 14 | local pid=$1 15 | [ -z $pid ] && return 16 | 17 | kill $pid 2> /dev/null 18 | while kill -s 0 $pid 2> /dev/null; do 19 | sleep 1 20 | done 21 | } 22 | 23 | log() { 24 | if [ -z "$2" ] 25 | then 26 | printf -- "%s %s\n" "[$(date)]" "$1" 27 | fi 28 | } 29 | 30 | while [ ${#} -gt 0 ]; do 31 | case "${1}" in 32 | -h|--help) 33 | usage 34 | ;; 35 | -f|--force) 36 | FORCE="--force" 37 | ;; 38 | -i) 39 | shift 40 | ;; 41 | -d|--domain) 42 | if [ -z "$2" ] || [ "${2:0:1}" = "-" ]; then 43 | echo "Domain required" 44 | usage 45 | fi 46 | DOMAIN+=("$2") 47 | shift 48 | ;; 49 | --debug) 50 | if [ -z "$2" ] || [ "${2:0:1}" = "-" ]; then 51 | DEBUG="--debug 1" 52 | else 53 | DEBUG="--debug ${2}" 54 | shift 55 | fi 56 | ;; 57 | *) 58 | echo "Unknown parameter : ${1}" 59 | usage 60 | ;; 61 | esac 62 | shift 1 63 | done 64 | 65 | # check for required parameters 66 | if [ ${#DOMAIN[@]} -eq 0 ]; then 67 | echo "Domain required" 68 | usage 69 | fi 70 | 71 | # prepare our domain flags for acme.sh 72 | for val in "${DOMAIN[@]}"; do 73 | DOMAINARG+="-d $val " 74 | done 75 | 76 | ACMEHOME=/config/.acme.sh 77 | 78 | mkdir -p $ACMEHOME/webroot 79 | 80 | ( 81 | cat <$ACMEHOME/lighttpd.conf 92 | 93 | log "Stopping GUI service." 94 | if [ -e "/var/run/lighttpd.pid" ]; then 95 | kill_and_wait $(cat /var/run/lighttpd.pid) 96 | fi 97 | 98 | log "Starting temporary ACME challenge service." 99 | /usr/sbin/lighttpd -f $ACMEHOME/lighttpd.conf 100 | 101 | /sbin/iptables -I INPUT 1 -p tcp -m comment --comment TEMP_LETSENCRYPT -m tcp --dport 80 -j ACCEPT 102 | /sbin/ip6tables -I INPUT 1 -p tcp -m comment --comment TEMP_LETSENCRYPT -m tcp --dport 80 -j ACCEPT 103 | /sbin/iptables -t nat -I PREROUTING 1 -p tcp -m comment --comment TEMP_LETSENCRYPT -m tcp --dport 80 -j ACCEPT 104 | mkdir -p /config/ssl 105 | # trick sudo detection in acme.sh 106 | unset SUDO_COMMAND 107 | $ACMEHOME/acme.sh --issue $DOMAINARG -w $ACMEHOME/webroot --home $ACMEHOME \ 108 | --reloadcmd "cat $ACMEHOME/${DOMAIN[0]}/${DOMAIN[0]}.cer $ACMEHOME/${DOMAIN[0]}/${DOMAIN[0]}.key > /config/ssl/server.pem; cp $ACMEHOME/${DOMAIN[0]}/ca.cer /config/ssl/ca.pem" \ 109 | --server letsencrypt ${FORCE} ${DEBUG} 110 | /sbin/iptables -D INPUT -p tcp -m comment --comment TEMP_LETSENCRYPT -m tcp --dport 80 -j ACCEPT 111 | /sbin/ip6tables -D INPUT -p tcp -m comment --comment TEMP_LETSENCRYPT -m tcp --dport 80 -j ACCEPT 112 | /sbin/iptables -t nat -D PREROUTING 1 113 | 114 | log "Stopping temporary ACME challenge service." 115 | if [ -e "$ACMEHOME/lighttpd.pid" ]; then 116 | kill_and_wait $(cat $ACMEHOME/lighttpd.pid) 117 | fi 118 | 119 | log "Starting GUI service." 120 | if [ -x "/bin/systemctl" ]; then 121 | /bin/systemctl start lighttpd.service 122 | else 123 | /usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf 124 | fi 125 | --------------------------------------------------------------------------------