.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "NGINX-CONFGEN 1" .TH NGINX-CONFGEN 1 "2020-10-28" "nginx-confgen-2.0" "nginx-confgen manual" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" nginx\-confgen \- A preprocessor and macro system for nginx(\-like) configuration files. .SH "SYNOPSIS" .IX Header "SYNOPSIS" nginx-confgen \-i input.conf \-o output.conf .SH "DESCRIPTION" .IX Header "DESCRIPTION" nginx-confgen can be used to do pre-processing for nginx configuration files (and other configuration files with a similar syntax). It has support for \&\*(L"compile-time\*(R" macro expansion and variable interpolation, which should make it less tedious to maintain large and complex configurations. .PP nginx-confgen 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 \*(L"\s-1BUGS & WARTS\*(R"\s0 below. .PP \&\fB\s-1WARNING:\s0\fR Do \s-1NOT\s0 use nginx-confgen with untrusted input, the \f(CW\*(C`pre_exec\*(C'\fR directive allows, by design, arbitrary code execution. .SH "OPTIONS" .IX Header "OPTIONS" The following command-line options are supported: .IP "\-h" 4 .IX Item "-h" Show help text. .IP "\-V, \-\-version" 4 .IX Item "-V, --version" Show program version. .IP "\-i \fI\s-1FILE\s0\fR" 4 .IX Item "-i FILE" Use the given file name as input file. If this option is not given or set to \&\f(CW\*(C`\-\*(C'\fR, then the file will be read from standard input. .IP "\-o \fI\s-1FILE\s0\fR" 4 .IX Item "-o FILE" Write the output to the given file. If this option is not given or set to \f(CW\*(C`\-\*(C'\fR, then the file will be written to standard output. .IP "\-I \fI\s-1DIR\s0\fR" 4 .IX Item "-I DIR" Set the search path for \fIpre_include\fR 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. \f(CW\*(C`\-I .\*(C'\fR). .SH "DIRECTIVES" .IX Header "DIRECTIVES" nginx-confgen recognizes and interprets the following directives: .SS "pre_include" .IX Subsection "pre_include" Similar to the \f(CW\*(C`include\*(C'\fR directive in nginx, except that the file is included during preprocessing. The included file may contain any preprocessing directives supported by nginx-confgen. 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 \f(CW\*(C`\-I\*(C'\fR flag. .SS "pre_set" .IX Subsection "pre_set" Similar to the \f(CW\*(C`set\*(C'\fR directive in nginx, except that variables defined with \&\f(CW\*(C`pre_set\*(C'\fR are resolved during preprocessing. Variables are set in the order that they are encountered in the configuration file, regardless of scoping. For example: .PP .Vb 5 \& pre_set $var outer; \& location / { \& pre_set $var inner; \& } \& # $var is "inner" at this point. .Ve .PP Only variables that are known to nginx-confgen will be substituted, unknown variables are assumed to be run-time variables for nginx and will be left alone without warning. For example: .PP .Vb 3 \& pre_set $ip 127.0.0.1; \& deny $ip; # This will output as: block 127.0.0.1; \& deny $otherip; # This will output as: block $otherip; .Ve .SS "pre_exec" .IX Subsection "pre_exec" Run a shell command, and store the output in a variable. For example, nginx will not use your system's \s-1DNS\s0 resolution methods to resolve domain names. Instead you need to manually set a \f(CW\*(C`resolver\*(C'\fR address. With the following hack you can fetch the nameserver from \f(CW\*(C`/etc/resolv.conf\*(C'\fR and use that as the \&\f(CW\*(C`resolver\*(C'\fR: .PP .Vb 3 \& pre_exec $nameserver "grep nameserver /etc/resolv.conf \e\e \& | head \-n 1 | sed \*(Aqs/^nameserver //\*(Aq"; \& resolver $nameserver; .Ve .PP (The \f(CW\*(C`\e\e\*(C'\fR is necessary, otherwise your shell will consider the newline as a new command). .SS "pre_if" .IX Subsection "pre_if" Similar to the \f(CW\*(C`if\*(C'\fR directive in nginx, except that this is evaluated during preprocessing. Braces around the condition are optional. Some examples: .PP .Vb 7 \& 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 \*(Aqhostname\*(Aq; \& pre_if $hostname ~* ^proxy_for_(.+) { \& proxy_pass http://$1/; \& } .Ve .SS "pre_warn" .IX Subsection "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: .PP .Vb 3 \& pre_if \-e /etc/offline\-mode { \& pre_warn "Putting website in offline mode!"; \& } .Ve .PP Or to warn about certain directives: .PP .Vb 2 \& pre_macro proxy_cache $var { \& pre_warn "Using proxy_cache with $var violates company policy!"; \& \& # But we can output it anyway. \& proxy_cache $var; \& } .Ve .SS "macro" .IX Subsection "macro" Define a \fImacro\fR, which is a configuration block that you can later refer to. The general syntax is as follows: .PP .Vb 3 \& macro macro_name $var1 $var2 @remaining_vars &block_var { \& # contents \& } .Ve .PP The optional \f(CW@remaining_vars\fR argument will capture any number of variables and can be passed to another directive inside the macro contents. The optional \&\f(CW&block_var\fR allows the macro to be invoked with a block argument, which will expand to any number of directives. Some examples: .PP .Vb 7 \& 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; \& } .Ve .PP Note that these are \fIhygienic\fR macros, so variable capture is predictable (but not necessarily the most useful): .PP .Vb 8 \& 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 \*(Aq/a\*(Aq inside the macro after this new variable definition. \& pre_var $dest /b; \& redir; .Ve .PP Similarly, macro arguments will not be available inside \f(CW&block\fR expansion or nested macro expansion and any variables set inside a macro will not be available outside of the macro body. .SH "BUGS & WARTS" .IX Header "BUGS & WARTS" nginx-confgen 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 may 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 \fItypes\fR directive in \fIngx_http_core_module\fR. While nginx-confgen should be able to handle the \fItypes\fR directive just fine, other extensions may cause syntax errors or will not survive a round-trip through nginx-confgen. This applies to all \fI*_by_lua_block\fR directives in the \fIngx_http_lua_module\fR. The \fI_by_lua\fR directives that accept a string should work just fine. .SH "AUTHOR" .IX Header "AUTHOR" nginx-confgen is written by Yoran Heling .PP Web: