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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
.\" SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
.\" SPDX-License-Identifier: MIT
.Dd October 22, 2024
.Dt NGINX\-CONFGEN 1
.Os
.Sh NAME
.Nm nginx\-confgen
.Nd A preprocessor and macro system for nginx(-like) configuration files
.Sh SYNOPSIS
.Nm
.Op Fl i Ar input.conf
.Op Fl o Ar output.conf
.Op Fl I Ar path
.Sh DESCRIPTION
.Nm
can be used to do pre-processing for nginx configuration files (and other
configuration files with a similar syntax).
It has support for "compile-time" macro expansion and variable interpolation,
which should make it less tedious to maintain large and complex configurations.
.Pp
.Nm
works by parsing the input into a syntax tree, modifying this tree, and then
formatting the tree to generate the output.
It is completely oblivious to nginx contexts and directives, so it is possible
to do nonsensical transformations and generate incorrect configuration files.
Comments in the input file will not be present in the output.
See also the
.Sx BUGS & WARTS
below.
.Pp
.Sy SECURITY CONSIDERATION :
Do NOT use nginx-confgen with untrusted input, the
.Cm pre_exec
directive allows arbitrary code execution by design.
.Sh OPTIONS
The following command-line options are supported:
.Bl -tag -width Ds
.It Fl h
Show help text.
.It Fl v , Fl \-version
Show program version.
.It Fl i Ar file
Use the given file name as input file.
If this option is not given or set to a dash (\-), then the file will be read
from standard input.
.It Fl o Ar file
Write the output to the given file.
If this option is not given or set to a dash (\-), then the file will be
written to standard output.
.It Fl I Ar path
Set the search path for
.Cm pre_include
directives.
This option can be given multiple times to search several directories in order.
If this option is not given, then include files are resolved relative to the
directory that nginx-confgen is run from (i.e. "\-I .").
.El
.Sh DIRECTIVES
.Nm
recognizes and interprets the following directives:
.Ss Cm pre_include
Similar to the
.Cm include
directive in nginx, except that the file is included during preprocessing.
The included file may contain any preprocessing directives supported by
.Nm .
Variables and macros defined in the included file will be available in the
parent file.
.Pp
Relative paths are searched for in the directories given with the
.Fl I
flag.
.Ss Cm pre_set
Similar to the
.Cm set
directive in nginx, except that variables defined with
.Cm pre_set
are resolved during preprocessing.
Variables are set in the order that they are encountered in the configuration
file, regardless of scoping.
For example:
.Bd -literal -offset indent
pre_set $var outer;
location / {
pre_set $var inner;
}
# $var is "inner" at this point.
.Ed
Only variables that are known to
.Nm
will be substituted, unknown variables are assumed to be run-time variables for
nginx and will be left alone without warning.
For example:
.Bd -literal -offset indent
pre_set $ip 127.0.0.1;
deny $ip; # This will output as: deny 127.0.0.1;
deny $otherip; # This will output as: deny $otherip;
.Ed
.Ss Cm pre_exec
Run a shell command and store the output in a variable.
For example, nginx will not use your system's DNS resolution methods to resolve
domain names, instead you need to manually set a
.Cm resolver
address.
With the following hack you can fetch the nameserver from
.Pa /etc/resolv.conf
and use that as the
.Cm resolver :
.Bd -literal -offset indent
pre_exec $nameserver "grep nameserver /etc/resolv.conf \\
| head -n 1 | sed 's/^nameserver //'";
resolver $nameserver;
.Ed
(The "\\" is necessary, otherwise your shell will consider the newline as a new
command).
.Ss Cm pre_if
Similar to the
.Cm if
directive in nginx, except that this is evaluated during preprocessing.
Braces around the condition are optional.
Some examples:
.Bd -literal -offset indent
pre_if -f $certdir/ocsp.der {
ssl_stapling on;
ssl_stapling_file $certdir/ocsp.der;
}
pre_if (!-f $certdir/ocsp.der) {
ssl_stapling off;
}
# You can have different configuration depending on the name of
# the system on which nginx-confgen runs. Like... yeah.
pre_exec $hostname 'hostname';
pre_if $hostname ~* ^proxy_for_(.+) {
proxy_pass http://$1/;
}
.Ed
.Ss Cm pre_warn
This directive, when interpreted, will generate a warning to the standard error
of nginx-confgen.
Can be used to signal that a special configuration is being used:
.Bd -literal -offset indent
pre_if -e /etc/offline-mode {
pre_warn "Putting website in offline mode!";
}
.Ed
Or to warn about certain directives:
.Bd -literal -offset indent
pre_macro proxy_cache $var {
pre_warn "Using proxy_cache with $var violates company policy!";
# But we can output it anyway.
proxy_cache $var;
}
.Ed
.Ss Cm macro
Define a macro, which is a configuration block that you can later refer to.
The general syntax is as follows:
.Bd -literal -offset indent
macro macro_name $var1 $var2 @remaining_vars &block_var {
# contents
}
.Ed
The optional
.Ar @remaining_vars
argument will capture any number of variables and can be passed to another
directive inside the macro contents.
.Ar $#remaining_vars
syntax expands to the number of arguments passed to the macro.
The optional
.Ar &block_var
allows the macro to be invoked with a block argument, which will expand to any
number of directives.
Some examples:
.Bd -literal -offset indent
macro le {
location /.well-known/acme-challenge {
alias /etc/letsencrypt/challenge;
}
}
# Usage:
le;
macro redir $path $to {
location $path {
return 301 $to;
}
}
# Usage:
redir / http://blicky.net/;
macro vhost $primary_name @aliases &block {
server {
listen [::]:443 ssl;
server_name $primary_name @aliases;
ssl_certificate $crtdir/$primary_name/fullchain.pem;
ssl_certificate_key $crtdir/$primary_name/privkey.pem;
█
}
}
# Usage:
vhost example.com {
root /var/www/example.com;
}
vhost example.org alias.example.org {
root /var/www/example.org;
}
.Ed
Note that these are
.Em hygienic
macros, so variable capture is predictable (but not necessarily the most
useful):
.Bd -literal -offset indent
pre_var $dest /a;
macro redir {
# This will be /a, regardless of the context in which this macro is called.
return 301 $dest;
}
# $dest is still '/a' inside the macro after this new variable definition.
pre_var $dest /b;
redir;
.Ed
Similarly, macro arguments will not be available inside
.Ar &block
expansion or nested macro expansion and any variables set inside a macro will
not be available outside of the macro body.
.Sh BUGS & WARTS
.Nm
is a quickly written hack to solve a particular use case, it is quite likely to
have some weird behavior and bugs.
In particular, processing performance may suffer on large configuration files
with many macros and/or variables.
Performance has simply not been a problem for me, but if you do run into
trouble with your use case, let me know so I can fix it.
.Pp
Comments and whitespace in the input files are thrown away and ignored.
The generated output is completely reformatted.
.Pp
The nginx configuration syntax is not as regular as I had hoped.
It's possible for nginx modules to extend the syntax somewhat.
A good example is the
.Cm types
directive in
.Cm ngx_http_core_module .
While nginx-confgen should be able to handle the
.Cm types
directive just fine, other extensions may cause syntax errors or will not
survive a round-trip through
.Nm .
This applies to all
.Cm *_by_lua_block
directives in the
.Em ngx_http_lua_module .
The
.Cm _by_lua
directives that accept a string should work just fine.
.Sh SEE ALSO
.Xr nginx 8
.Pp
.Nm
has a website:
.Lk https://dev.yorhel.nl/nginx-confgen
.Sh AUTHORS
Written by
.An Yorhel Aq Mt projects@yorhel.nl
|