My NAS - Part 2
Dynamic DNS, ACME and SSL Web Servers
Define Our Variables
We’re going to define a few variables to make this easier for you. Replace the value of each variable before continuing:
1
2
3
4
5
6
export DOMAIN=example.com
export USERNAME=username
export PASSWORD=password
export DYNU_CLIENT_ID=REDACTED
export DYNU_SECRET=REDACTED
export EMAIL=username@example.com
Dynamic DNS (DDNS) service
I signed up for free domain name via DynU. You can too! The DDNS service that I am listing in this part of my NAS series uses DynU as the DDNS host. Alternative hosts require a different configuration than what is shown.
Let’s install the DDNS service, as well as the LUCI app:
1
apk add luci-app-ddns bind-host
Because my NAS doesn’t sit at the gate of my home network like my router does, I can’t rely on using the IP address of an interface for the dynamic DNS address. So I have to tell the service to check http://checkip.dyndns.com instead. With this in mind, we need to configure the service, then restart the service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
uci -q del ddns.global.upd_privateip
uci set ddns.global.ddns_rundir='/var/run/ddns'
uci set ddns.global.ddns_logdir='/var/log/ddns'
uci -q del ddns.myddns_ipv4
uci -q del ddns.myddns_ipv6
uci set ddns.Home=service
uci set ddns.Home.enabled='1'
uci set ddns.Home.lookup_host=${DOMAIN}
uci set ddns.Home.domain=${DOMAIN}
uci set ddns.Home.username=${USERNAME}
uci set ddns.Home.password=${PASSWORD}
uci set ddns.Home.use_https='1'
uci set ddns.Home.cacert='/etc/ssl/certs'
uci set ddns.Home.use_logfile='0'
uci set ddns.Home.check_interval='1'
uci set ddns.Home.update_url='http://api.dynu.com/nic/update?hostname=[DOMAIN]&myip=[IP]&username=[USERNAME]&password=[PASSWORD]'
uci set ddns.Home.force_interval='2'
uci set ddns.NAS.ip_source='web'
uci set ddns.NAS.ip_url='http://checkip.dyndns.com'
uci set ddns.Home.use_syslog='2'
uci set ddns.Home.check_unit='minutes'
uci set ddns.Home.force_unit='minutes'
uci set ddns.Home.retry_unit='seconds'
uci commit
service ddns restart
Get a SSL Certificate from Let’s Encrypt
Let’s install the ACME program and LUCI app:
1
apk add luci-app-acme acme-acmesh-dnsapi
We need to rebuild the ACME configuration file, since it contains garbage that I don’t want in the firmware I is building. Once completed, the ACME service needs to be restarted.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cp /dev/null /etc/config/acme
uci set acme.server=acme
uci set acme.server.account_email=${EMAIL}
uci set acme.server.debug='0'
export SECTION=${DOMAIN//\./_}
uci set acme.${SECTION}=cert
uci set acme.${SECTION}.enabled='1'
uci add_list acme.${SECTION}.domains=${DOMAIN}
uci add_list acme.${SECTION}.domains='*.'${DOMAIN}
uci set acme.${SECTION}.validation_method='dns'
uci set acme.${SECTION}.dns='dns_dynu'
uci add_list acme.${SECTION}.credentials='Dynu_ClientId="'${DYNU_CLIENT_ID}'"'
uci add_list acme.${SECTION}.credentials='Dynu_Secret="'${DYNU_SECRET}'"'
uci commit
service acme restart
service acme renew
Replace UHTTPD with NGINX
Let’s remove UHTTPD from the router and install NGINX. It’s going to be necessary to do some of the things I want to do:
1
2
opkg remove luci-light uhttpd-mod-ubus luci luci-ssl --force-removal-of-dependent-packages
opkg install nginx-full nginx-mod-luci luci-nginx luci-nginx
The initial /etc/config/nginx file contains templates and stuff that I don’t need. Let’s start over with that file!
1
2
3
cp /dev/null /etc/config/nginx
uci set nginx.global=main
uci set nginx.global.uci_enable='true'
We’ll define an default HTTP server that redirects HTTP requests to HTTPS:
1
2
3
4
5
uci set nginx.http_default=server
uci add_list nginx.http_default.listen='80 default_server'
uci add_list nginx.http_default.listen='[::]:80 default_server'
uci set nginx.http_default.server_name='_redirect2ssl'
uci set nginx.http_default.return='302 https://$host$request_uri'
We’ll define an HTTP server that redirects http://openwrt/, http://openwrt.lan, and http://openwrt.local to https://admin.example.com:
1
2
3
4
5
uci set nginx.http_router=server
uci add_list nginx.http_admin.listen='80'
uci add_list nginx.http_admin.listen='[::]:80'
uci set nginx.http_admin.server_name='openwrt.lan openwrt.local openwrt'
uci set nginx.http_admin.return='302 https://admin.'${DOMAIN}'$request_uri'
Default HTTPS redirects HTTPS requests to https://admin.example.com:
1
2
3
4
5
6
7
8
9
10
11
12
uci set nginx.https_default=server
uci add_list nginx.https_default.listen='443 ssl default_server'
uci add_list nginx.https_default.listen='[::]:443 ssl default_server'
uci set nginx.https_default.server_name='_lan'
uci add_list nginx.https_default.include='restrict_locally'
uci add_list nginx.https_default.include='conf.d/*.locations'
uci set nginx.https_default.ssl_certificate='/etc/acme/'${DOMAIN}'_ecc/'${DOMAIN}'.cer'
uci set nginx.https_default.ssl_certificate_key='/etc/acme/'${DOMAIN}'_ecc/'${DOMAIN}'.key'
uci set nginx.https_default.ssl_session_cache='shared:SSL:32k'
uci set nginx.https_default.ssl_session_timeout='64m'
uci set nginx.https_default.access_log='off; # logd openwrt'
uci set nginx.https_default.return='302 https://admin.'${DOMAIN}'$request_uri'
Let’s define the HTTPS server serving LUCI (https://admin.example.com):
1
2
3
4
5
6
7
8
9
10
11
uci set nginx.https_router=server
uci add_list nginx.https_admin.listen='443 ssl'
uci add_list nginx.https_admin.listen='[::]:443 ssl'
uci set nginx.https_admin.server_name='admin.'${DOMAIN}
uci add_list nginx.https_admin.include='restrict_locally'
uci add_list nginx.https_admin.include='conf.d/*.locations'
uci set nginx.https_admin.ssl_certificate='/etc/acme/'${DOMAIN}'_ecc/'${DOMAIN}'.cer'
uci set nginx.https_admin.ssl_certificate_key='/etc/acme/'${DOMAIN}'_ecc/'${DOMAIN}'.key'
uci set nginx.https_admin.ssl_session_cache='shared:SSL:32k'
uci set nginx.https_admin.ssl_session_timeout='64m'
uci set nginx.https_admin.access_log='off; # logd openwrt'
We need to commit these changes and restart NGNIX:
1
2
uci commit
service nginx restart
Adding a 403 error handler to NGINX
I’ve minified my version of the (IMHO: silly) error 403 html page from CodePen. Let’s download it for our router:
1
2
3
FILE=/www/error_403.html
wget https://xptsp.github.io/assets/files/error_403.template -O ${FILE}
echo ${FILE} >> /etc/sysupgrade.conf
We also need a 403 error handler block for NGINX. It converts any 403 error into a 404 error:
1
2
3
4
5
6
7
8
9
10
FILE=/etc/nginx/conf.d/error_403.locations
cat << EOF > ${FILE}
error_page 403 =404 /error_403.html;
location = /error_403.html {
root /www;
allow all;
internal;
}
EOF
echo ${FILE} >> /etc/sysupgrade.conf
Restart NGINX for it to show up when unauthorized access occurs:
1
service nginx restart
Summary
Now we have a NAS web server that encrypts all communication by default when using the proper domain name. Yay!

