blob: 7ca1729644fb4de118f3c878797c887dbf7bfc10 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/bin/sh
2# This is a template copy it by: ./README.sh | xclip -selection c
3# to https://openwrt.org/docs/guide-user/services/webserver/nginx#configuration
4
5
6NGINX_UTIL="/usr/bin/nginx-util"
7
8EXAMPLE_COM="example.com"
9
10MSG="
11/* Created by the following bash script that includes the source of some files:
12 * https://github.com/openwrt/packages/net/nginx-util/files/README.sh
13 */"
14
15eval $("${NGINX_UTIL}" get_env)
16
17code() {
18 local file
19 [ $# -gt 1 ] && file="$2" || file="$(basename "$1")"
20 printf "<file nginx %s>\n%s</file>" "$1" "$(cat "${file}")";
21}
22
23ifConfEcho() {
24 sed -nE "s/^\s*$1=\s*(\S*)\s*\\\\$/\n$2 \"\1\";/p" ../../nginx/Makefile;
25}
26
27cat <<EOF
28
29
30
31
32
33===== Configuration =====${MSG}
34
35
36
37The official Documentation contains a
38[[https://docs.nginx.com/nginx/admin-guide/|Admin Guide]].
39Here we will look at some often used configuration parts and how we handle them
40at OpenWrt.
41At different places there are references to the official
42[[https://docs.nginx.com/nginx/technical-specs/|Technical Specs]]
43for further reading.
44
45**tl;dr:** When starting Nginx by ''/etc/init.d/nginx'', it creates its main
46configuration dynamically based on a minimal template and the
47[[docs:guide-user:base-system:uci|🡒UCI]] configuration.
48
49The UCI ''/etc/config/nginx'' contains initially:
50| ''config server '${LAN_NAME}''' | \
51Default server for the LAN, which includes all ''${CONF_DIR}*.locations''. |
52| ''config server '_redirect2ssl''' | \
53Redirects inexistent URLs to HTTPS. |
54
55It enables also the ''${CONF_DIR}'' directory for further configuration:
56| ''${CONF_DIR}\$NAME.conf'' | \
57Is included in the main configuration. \
58It is prioritized over a UCI ''config server '\$NAME' ''. |
59| ''${CONF_DIR}\$NAME.locations'' | \
60Is include in the ''${LAN_NAME}'' server and can be re-used for others, too. |
61| ''$(dirname "${CONF_DIR}")/restrict_locally'' | \
62Is include in the ''${LAN_NAME}'' server and allows only accesses from LAN. |
63
64Setup configuration (for a server ''\$NAME''):
65| ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$NAME'' | \
66Add/remove a self-signed certificate and corresponding directives. |
67| ''uci set nginx.\$NAME.access_log='logd openwrt''' | \
68Writes accesses to Openwrt’s \
69[[docs:guide-user:base-system:log.essentials|🡒logd]]. |
70| ''uci set nginx.\$NAME.error_log='logd' '' | \
71Writes errors to Openwrt’s \
72[[docs:guide-user:base-system:log.essentials|🡒logd]]. |
73| ''uci [set|add_list] nginx.\$NAME.key='value' '' | \
74Becomes a ''key value;'' directive if the //key// does not start with //uci_//. |
75| ''uci set nginx.\$NAME=[disable|server]'' |\
76Disable/enable inclusion in the dynamic conf.|
77| ''uci set nginx.global.uci_enable=false'' | \
78Use a custom ''${NGINX_CONF}'' rather than a dynamic conf. |
79
80
81
82==== Basic ====${MSG}
83
84
85We modify the configuration by changing servers saved in the UCI configuration
86at ''/etc/config/nginx'' and/or by creating different configuration files in the
87''${CONF_DIR}'' directory.
88These files use the file extensions ''.locations'' and ''.conf'' plus ''.crt''
89and ''.key'' for SSL certificates and keys.((
90We can disable a single configuration file in ''${CONF_DIR}'' by giving it
91another extension, e.g., by adding ''.disabled''.))
92For the new configuration to take effect, we must reload it by:
93
94<code bash>service nginx reload</code>
95
96For OpenWrt we use a special initial configuration, which is explained in the
97section [[#openwrt_s_defaults|🡓OpenWrt’s Defaults]].
98So, we can make a site available at a specific URL in the **LAN** by creating a
99''.locations'' file in the directory ''${CONF_DIR}''.
100Such a file consists just of some
101[[https://nginx.org/en/docs/http/ngx_http_core_module.html#location|
102location blocks]].
103Under the latter link, you can find also the official documentation for all
104available directives of the HTTP core of Nginx.
105Look for //location// in the Context list.
106
107The following example provides a simple template, see at the end for
108different [[#locations_for_apps|🡓Locations for Apps]]((look for
109[[https://github.com/search?utf8=%E2%9C%93&q=repo%3Aopenwrt%2Fpackages
110+extension%3Alocations&type=Code&ref=advsearch&l=&l=|
111other packages using a .locations file]], too.)):
112
113<code nginx ${CONF_DIR}example.locations>
114location /ex/am/ple {
115 access_log off; # default: not logging accesses.
116 # access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
117 # error_log stderr; # default: logging to logd (init forwards stderr).
118 error_log /dev/null; # disable error logging after config file is read.
119 # (state path of a file for access_log/error_log to the file instead.)
120 index index.html;
121}
122# location /eg/static { … }
123</code>
124
125All location blocks in all ''.locations'' files must use different URLs,
126since they are all included in the ''${LAN_NAME}'' server that is part of the
127[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]].((
128We reserve the ''location /'' for making LuCI available under the root URL,
129e.g. [[https://192.168.1.1/|192.168.1.1/]].
130All other sites shouldn’t use the root ''location /'' without suffix.))
131We should use the root URL for other sites than LuCI only on **other** domain
132names, e.g., we could make a site available at https://${EXAMPLE_COM}/.
133In order to do that, we create [[#new_server_parts|🡓New Server Parts]] for all
134domain names.
135We can also activate SSL thereby, see
136[[#ssl_server_parts|🡓SSL Server Parts]].
137We use such server parts also for publishing sites to the internet (WAN)
138instead of making them available just locally (in the LAN).
139
140Via ''${CONF_DIR}*.conf'' files we can add directives to the //http// part of
141the configuration.
142If you would change the configuration ''$(basename "${UCI_CONF}").template''
143instead, it is not updated to new package's versions anymore.
144Although it is not recommended, you can also disable the whole UCI config and
145create your own ''${NGINX_CONF}''; then invoke:
146
147<code bash>uci set nginx.global.uci_enable=false</code>
148
149
150
151==== New Server Parts ====${MSG}
152
153
154For making the router reachable from the WAN at a registered domain name,
155it is not enough letting the
156[[docs:guide-user:firewall:firewall_configuration|🡒firewall]] accept requests
157(typically on ports 80 and 443) and giving the name server the internet IP
158address of the router (maybe updated automatically by a
159[[docs:guide-user:services:ddns:client|🡒DDNS Client]]).
160
161We also need to set up virtual hosting for this domain name by creating an
162appropriate server section in ''/etc/config/nginx''
163(or in a ''${CONF_DIR}*.conf'' file, which cannot be changed using UCI).
164All such parts are included in the main configuration of OpenWrt
165([[#openwrt_s_defaults|🡓OpenWrt’s Defaults]]).
166
167In the server part, we state the domain as
168[[https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name|
169server_name]].
170The link points to the same document as for the location blocks in the
171[[#basic|🡑Basic Configuration]]: the official documentation for all available
172directives of the HTTP core of Nginx.
173This time look for //server// in the Context list, too.
174The server part should also contain similar location blocks as
175++before.|
176We can re-include a ''.locations'' file that is included in the server part for
177the LAN by default.
178Then the site is reachable under the same path at both domains, e.g. by
179https://192.168.1.1/ex/am/ple as well as by https://${EXAMPLE_COM}/ex/am/ple.
180++
181
182We can add directives to a server in the UCI configuration by invoking
183''uci [set|add_list] nginx.${EXAMPLE_COM//./_}.key=value''.
184If the //key// is not starting with //uci_//, it becomes a ''key value;''
185++directive.|
186Although the UCI config does not support nesting like Nginx, we can add a whole
187block as //value//.
188++
189
190We cannot use dots in a //key// name other than in the //value//.
191In the following example we replace the dot in //${EXAMPLE_COM}// by an
192underscore for the UCI name of the server, but not for Nginx's //server_name//:
193
194<code bash>
195uci add nginx server &&
196uci rename nginx.@server[-1]=${EXAMPLE_COM//./_} &&
197uci add_list nginx.${EXAMPLE_COM//./_}.listen='80' &&
198uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' &&
199uci set nginx.${EXAMPLE_COM//./_}.server_name='${EXAMPLE_COM}' &&
200uci add_list nginx.${EXAMPLE_COM//./_}.include=\
201'$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations'
202# uci add_list nginx.${EXAMPLE_COM//./_}.location='/ { … }' \
203# root location for this server.
204</code>
205
206We can disable respective re-enable this server again by:
207
208<code bash>
209uci set nginx.${EXAMPLE_COM//./_}=disable # respective: \
210uci set nginx.${EXAMPLE_COM//./_}=server
211</code>
212
213These changes are made in the RAM (and can be used until a reboot), we can save
214them permanently by:
215
216<code bash>uci commit nginx</code>
217
218For creating a similar ''${CONF_DIR}${EXAMPLE_COM}.conf'', we can adopt the
219following:
220
221<code nginx ${CONF_DIR}${EXAMPLE_COM}.conf>
222server {
223 listen 80;
224 listen [::]:80;
225 server_name ${EXAMPLE_COM};
226 include '$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations';
227 # location / { … } # root location for this server.
228}
229</code>
230
231[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include the UCI server
232''config server '_redirect2ssl' ''.
233It acts as //default_server// for HTTP and redirects requests for inexistent
234URLs to HTTPS.
235For making another domain name accessible to all addresses, the corresponding
236server part should listen on port //80// and contain the FQDN as
237//server_name//, cf. the official documentation on
238[[https://nginx.org/en/docs/http/request_processing.html|request_processing]].
239
240Furthermore, there is a UCI server named ''${LAN_NAME}''.
241It is the //default_server// for HTTPS and allows connections from LAN only.
242It includes the file ''$(dirname "${CONF_DIR}")/restrict_locally'' with
243appropriate //allow/deny// directives, cf. the official documentation on
244[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]].
245
246
247
248==== SSL Server Parts ====${MSG}
249
250
251For enabling HTTPS for a domain we need a SSL certificate as well as its key and
252add them by the directives //ssl_certificate// respective
253//ssl_certificate_key// to the server part of the domain
254([[https://nginx.org/en/docs/http/configuring_https_servers.html#sni|TLS SNI]]
255is supported by default).
256The rest of the configuration is similar as for general
257[[#new_server_parts|🡑New Server Parts]].
258We only have to adjust the listen directives by adding the //ssl// parameter and
259changing the port from //80// to //443//.
260
261The official documentation of the SSL module contains an
262[[https://nginx.org/en/docs/http/ngx_http_ssl_module.html#example|
263example]] with some optimizations.
264We can extend an existing UCI server section similarly, e.g., for the above
265''config server '${EXAMPLE_COM//./_}' '' we invoke:
266
267<code bash>
268# Instead of 'del_list' the listen* entries, we could use '443 ssl' beforehand.
269uci del_list nginx.${EXAMPLE_COM//./_}.listen='80' &&
270uci del_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' &&
271uci add_list nginx.${EXAMPLE_COM//./_}.listen='443 ssl' &&
272uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:443 ssl' &&
273uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate=\
274'${CONF_DIR}${EXAMPLE_COM}.crt' &&
275uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate_key=\
276'${CONF_DIR}${EXAMPLE_COM}.key' &&
277uci set nginx.${EXAMPLE_COM//./_}.ssl_session_cache=\
278'${SSL_SESSION_CACHE_ARG}' &&
279uci set nginx.${EXAMPLE_COM//./_}.ssl_session_timeout=\
280'${SSL_SESSION_TIMEOUT_ARG}' &&
281uci commit nginx
282</code>
283
284For making the server in ''${CONF_DIR}${EXAMPLE_COM}.conf'' available
285via SSL, we can make similar changes there.
286
287The following command creates a **self-signed** SSL certificate and changes the
288corresponding configuration:
289
290<code bash>$(basename "${NGINX_UTIL}") ${ADD_SSL_FCT} ${EXAMPLE_COM}</code>
291
292 - If a ''$(basename "${CONF_DIR}")/${EXAMPLE_COM}.conf'' file exists, it\
293 adds //ssl_*// directives and changes the //listen// directives there.\
294 Else it does that similarly to the example above for a ++selected UCI\
295 server.| Hereby it searches the UCI config first for a server with the\
296 given name and then for a server whose //server_name// contains the name.\
297 For //${EXAMPLE_COM}// it is the latter as a UCI key cannot have dots.++
298 - It checks if there is a certificate with key for '${EXAMPLE_COM}' that is\
299 valid for at least 13 months or tries to create a self-signed one.
300 - When cron is activated, it installs a cron job for renewing the self-signed\
301 certificate every year if needed, too. We can activate cron by: \
302 <code bash>service cron enable && service cron start</code>
303
304This can be undone by invoking:
305
306<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM}</code>
307
308For using an SSL certificate and key that are managed otherwise, there is:
309
310<code bash>$(basename "${NGINX_UTIL}") add_ssl ${EXAMPLE_COM} "\$MANAGER" \
311"/absolute/path/to/crt" "/absolute/path/to/key"</code>
312
313It only adds //ssl_*// directives and changes the //listen// directives in
314the appropriate configuration, but does not create or change the certificate
315or its key. This can be reverted by:
316
317<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM} "\$MANAGER"</code>
318
319For example [[https://github.com/ndilieto/uacme|uacme]] or
320[[https://github.com/Neilpang/acme.sh|acme.sh]] can be used for creating an SSL
321certificate signed by Let’s Encrypt and changing the config
322++accordingly.|
323They call ''$(basename "${NGINX_UTIL}") add_ssl \$FQDN acme \$CRT \$KEY''
324internally.++
325We can install them by:
326
327<code bash>
328opkg update && opkg install uacme #or: acme #and for LuCI: luci-app-acme
329</code>
330
331[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include a UCI server for the LAN:
332''config server '${LAN_NAME}' ''.
333It has //ssl_*// directives prepared for a self-signed((Let’s Encrypt (and other
334CAs) cannot sign certificates of a **local** server.))
335SSL certificate, which is created on the first start of Nginx.
336The server listens on all addresses, is the //default_server// for HTTPS and
337allows connections from LAN only (by including the file ''restrict_locally''
338with //allow/deny// directives, cf. the official documentation on
339[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]]).
340
341For making another domain name accessible to all addresses, the corresponding
342SSL server part should listen on port //443// and contain the FQDN as
343//server_name//, cf. the official documentation on
344[[https://nginx.org/en/docs/http/request_processing.html|request_processing]].
345
346Furthermore, there is also a UCI server named ''_redirect2ssl'', which listens
347on all addresses, acts as //default_server// for HTTP and redirects requests for
348inexistent URLs to HTTPS.
349
350
351
352==== OpenWrt’s Defaults ====${MSG}
353
354
355Since Nginx is compiled with these presets, we can pretend that the main
356configuration will always contain the following directives
357(though we can overwrite them):
358
359<code nginx>$(ifConfEcho --pid-path pid)\
360$(ifConfEcho --lock-path lock_file)\
361$(ifConfEcho --error-log-path error_log)\
362$(false && ifConfEcho --http-log-path access_log)\
363$(ifConfEcho --http-proxy-temp-path proxy_temp_path)\
364$(ifConfEcho --http-client-body-temp-path client_body_temp_path)\
365$(ifConfEcho --http-fastcgi-temp-path fastcgi_temp_path)\
366</code>
367
368When starting or reloading the Nginx service, the ''/etc/init.d/nginx'' script
369sets also the following directives
370(so we cannot change them in the used configuration file):
371
372<code nginx>
373daemon off; # procd expects services to run in the foreground
374</code>
375
376Then, the init sript creates the main configuration
377''$(basename "${UCI_CONF}")'' dynamically from the template:
378
379$(code "${UCI_CONF}.template")
380
381So, the access log is turned off by default and we can look at the error log
382by ''logread'', as init.d script forwards stderr and stdout to the
383[[docs:guide-user:base-system:log.essentials|🡒runtime log]].
384We can set the //error_log// and //access_log// to files, where the log
385messages are forwarded to instead (after the configuration is read).
386And for redirecting the access log of a //server// or //location// to the logd,
387too, we insert the following directive in the corresponding block:
388
389<code nginx> access_log /proc/self/fd/1 openwrt;</code>
390
391If we setup a server through UCI, we can use the options //error_log// and/or
392//access_log// also with the special path
393++'logd'.|
394When initializing the Nginx service, this special path is replaced by //stderr//
395respective ///proc/self/fd/1// (which are forwarded to the runtime log).
396++
397
398For creating the configuration from the template shown above, Nginx’s init
399script replaces the comment ''#UCI_HTTP_CONFIG'' by all UCI servers.
400For each server section in the the UCI configuration, it basically copies all
401options into a Nginx //server { … }// part, in detail:
402 * Options starting with ''uci_'' are skipped. Currently there is only\
403 the ''option ${MANAGE_SSL}=…'' in ++usage.| It is set to\
404 //'self-signed'// when invoking\
405 ''$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} \$NAME''.\
406 Then the corresponding certificate is re-newed if it is about to expire.\
407 All those certificates are checked on the initialization of the Nginx service\
408 and if Cron is available, it is deployed for checking them annually, too.++
409 * All other lists or options of the form ''key='value' '' are written\
410 one-to-one as ''key value;'' directives to the configuration file.\
411 Just the path //logd// has a special meaning for the logging directives\
412 (described in the previous paragraph).
413
414The init.d script of Nginx uses the //$(basename ${NGINX_UTIL})// for creating
415the configuration file
416++in RAM.|
417The main configuration ''${UCI_CONF}'' is a symbolic link to this place
418(it is a dead link if the Nginx service is not running).
419++
420
421We could use a custom configuration created at ''${NGINX_CONF}'' instead of the
422dynamic configuration, too.((
423For using a custom configuration at ''${NGINX_CONF}'', we execute
424<code bash>uci set nginx.global.uci_enable='false' </code>
425Then the rest of the UCI config is ignored and //init.d// will not create the
426main configuration dynamically from the template anymore.
427Invoking ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$FQDN''
428will still try to change a server in ''$(basename "${CONF_DIR}")/\$FQDN.conf''
429(this is less reliable than for a UCI config as it uses regular expressions, not
430a complete parser for the Nginx configuration).))
431This is not encouraged since you cannot setup servers using UCI anymore.
432Rather, we can put custom configuration parts to ''.conf'' files in the
433''${CONF_DIR}'' directory.
434The main configuration pulls in all ''$(basename "${CONF_DIR}")/*.conf'' files
435into the //http {…}// block behind the created UCI servers.
436
437The initial UCI config is enabled and contains two server section:
438
439$(code "/etc/config/nginx" "nginx.config")
440
441While the LAN server is the //default_server// for HTTPS, the server
442redirecting requests for an inexistent ''server_name'' from HTTP to HTTPS acts
443as //default_server// if there is ++no other|;
444it uses an invalid name for that, more in the official documentation on
445[[https://nginx.org/en/docs/http/request_processing.html|request_processing]]
446++.
447
448The LAN server pulls in all ''.locations'' files from the directory
449''${CONF_DIR}''.
450We can install the location parts of different sites there (see
451[[#basic|🡑Basic Configuration]]) and re-include them into other servers.
452This is needed especially for making them available to the WAN
453([[#new_server_parts|🡑New Server Parts]]).
454The LAN server listens for all addresses on port //443// and restricts the
455access to local addresses by including:
456$(code "$(dirname "${CONF_DIR}")/restrict_locally")
457
458When starting or reloading the Nginx service, the init.d looks which UCI servers
459have set ''option ${MANAGE_SSL} 'self-signed' '', e.g. the LAN server.
460For all those servers it checks if there is a certificate that is still valid
461for 13 months or (re-)creates a self-signed one.
462If there is any such server, it installs also a cron job that checks the
463corresponding certificates once a year.
464The option ''${MANAGE_SSL}'' is set to //'self-signed'// respectively removed
465from a UCI server named ''${EXAMPLE_COM//./_}'' by the following
466(see [[#ssl_server_parts|🡑SSL Server Parts]], too):
467
468<code bash>
469$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} ${EXAMPLE_COM//./_} \
470# respectively: \
471$(basename ${NGINX_UTIL}) del_ssl ${EXAMPLE_COM//./_}
472</code>
473
474
475EOF