├── .gitignore ├── LICENSE ├── README.md ├── bakery.php ├── certificates └── README.md ├── config.php ├── cookbooks ├── bigace-v2.php ├── bigace-v3.php ├── cdn.php ├── jekyll-https.php ├── php-fpm.php ├── wordpress-https.php └── wordpress.php ├── default_site └── index.html ├── error_pages ├── 404.html └── 50x.html ├── ingredients ├── README.md ├── error │ ├── 404.conf │ └── 50x.conf ├── general │ ├── cache-assets.conf │ ├── deny-htaccess.conf │ ├── empty.conf │ ├── favicon.conf │ ├── hide-headers.conf │ ├── no-logs.conf │ ├── php-fpm.conf │ ├── robots.conf │ ├── security.conf │ └── ssl.conf ├── software │ ├── bigace-v2.conf │ ├── bigace-v3.conf │ ├── dokuwiki.conf │ ├── freshrss.conf │ ├── jekyll.conf │ ├── kimai.conf │ ├── piwik-tracking.conf │ ├── smf-v1.conf │ ├── smf-v2-prettyurls.conf │ ├── symfony4.conf │ └── yourls.conf └── wordpress │ ├── administration.conf │ ├── common.conf │ ├── hide-login.conf │ ├── php-fpm.conf │ └── redirect-ssl.conf ├── nginx └── README.md ├── recipes ├── 443-default.conf ├── 443-redirect_server.conf ├── 443-redirect_static.conf ├── 80-default.conf ├── 80-redirect_server.conf ├── 80-redirect_static.conf └── plaintext.conf └── sites.php.dist /.gitignore: -------------------------------------------------------------------------------- 1 | sites.php 2 | nginx/sites-enabled/* 3 | nginx/includes/* 4 | .idea 5 | config.local.php 6 | certificates/server.crt 7 | certificates/server.key 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Kevin Papst 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nginx-bakery 2 | ============ 3 | 4 | PHP scripts to create nginx config files from templates 5 | 6 | **_ATTENTION_: The nginx configs were not pimped by an experienced admin, therefor you should closely check the generated configs for your own needs.** 7 | 8 | This library can possibly help you, if you are managing a lot of virtual hosts. 9 | It has some basic logic for dynamic inclusion and using variables and mixins, stuff that is often refered as to "templating". 10 | 11 | If you start with nginx, you might stumble upon some basic problems, like the wish to use variables within your server definitions. 12 | All discussions point out, that nginx does not support this, because of runtime performance impacts. 13 | The recommended solution is to use a template system to generate your configs. As so often, I could not find anything ready-to-use, so I wrote this small library. 14 | 15 | I do manage manage ~30 (sub-)domains with different applications using these scripts (since years) and by the time of this writing, 16 | all have `A+` rating by several server test tools like the [Qualys SSL Labs Report](https://www.ssllabs.com/ssltest/analyze.html?d=www.kevinpapst.de&hideResults=on&latest). 17 | 18 | # Directories 19 | 20 | For the sake of out-of-the-box usage, all scripts rely on two paths: 21 | 22 | - /etc/nginx/ - as base configuration directory for nginx 23 | - /opt/nginx-bakery/ - as installation directory of this library 24 | 25 | # Installation 26 | 27 | ``` 28 | cd /opt/ 29 | git clone https://github.com/kevinpapst/nginx-bakery 30 | ``` 31 | 32 | ## Initial setup 33 | 34 | - Create "sites-php" with `cp sites.php.dist sites.php` and adjust `sites.php` to your needs 35 | - You can overwrite any part of the initial `config.php` by creating a `config.local.php` 36 | - Run `php bakery.php` 37 | - Enable your sites/servers/domains in nginx from the "nginx/sites-enabled" directory (some options are named below) 38 | 39 | ## Enable sites 40 | There are several ways on how to activate the generated configs ... use your imagination if you do not like the ones mentioned below :) 41 | 42 | 1. This is the most easy one and will work, if you manage all sites with this library: 43 | ``` 44 | mv /etc/nginx/sites-enabled /etc/nginx/backup_sites-enabled 45 | ln -s /opt/nginx-bakery/nginx/sites-enabled /etc/nginx/sites-enabled 46 | ln -s /opt/nginx-bakery/nginx/includes /etc/nginx/includes 47 | ``` 48 | 49 | 2. Or you could copy the files over to their new location: 50 | ``` 51 | cp -r /opt/nginx-bakery/nginx/includes /etc/nginx/ 52 | cp /opt/nginx-bakery/nginx/sites-enabled/* /etc/nginx/sites-enabled/ 53 | ``` 54 | 55 | # HOW-TO 56 | Lets start with a wording definition. 57 | 58 | nginx-bakery knows three different stages of configuration files: 59 | 1) cookbooks (a full set of several server definitions) 60 | 2) recipes (single server definitions) 61 | 3) ingredients (nginx includes) 62 | where each stage supports the usage of variables during the generation process. 63 | 64 | A set of server configurations and includes are "baked" - namely the process of parsing your configuration 65 | and creating static nginx config files and includes from your definitions. 66 | 67 | All your sites are defined in the file "sites.php". If you want to add cookbooks, recipes or ingredients, you need to adjust "config.php" by now. 68 | This might change in the future, but for now keeping them in a config file makes it easier to handle. 69 | 70 | 71 | ## Examples 72 | 73 | ### Certificate configuration 74 | 75 | Everyone nowadays should and hopefully does uses HTTPS sites. In nginx-bakery you configure your site certificates in the file `config.local.php`: 76 | 77 | ```php 78 | [ 81 | 'example.com' => [ 82 | 'crt' => '/etc/letsencrypt/live/example.com/fullchain.pem', 83 | 'key' => '/etc/letsencrypt/live/example.com/privkey.pem', 84 | ], 85 | ], 86 | ]; 87 | ``` 88 | 89 | ### Use a different PHP version 90 | 91 | So you are not using PHP 7.1 as configured in the default `config.php`? No problem, overwrite the key in your `config.local.php`: 92 | 93 | ```php 94 | [ 97 | 'php_fastcgi_pass' => 'unix:/run/php/php7.2-fpm.sock', 98 | ], 99 | ]; 100 | ``` 101 | 102 | -------------------------------------------------------------------------------- /bakery.php: -------------------------------------------------------------------------------- 1 | isDir() ? array($splFileInfo->getFilename() => array()) : array($splFileInfo->getFilename()); 46 | for ($depth = $ritit->getDepth() - 1; $depth >= 0; $depth--) { 47 | $path = array($ritit->getSubIterator($depth)->current()->getFilename() => $path); 48 | } 49 | $r = array_merge_recursive($r, $path); 50 | } 51 | 52 | // ==================================================================== 53 | // header, just to let people know where they can find more usage infos 54 | echo NXB_EOL . 'nginx-bakery '.NXB_VERSION.' - more infos at https://github.com/kevinpapst/nginx-bakery' . NXB_EOL; 55 | 56 | // ==================================================================== 57 | // now generate all of them and save them in the target directory 58 | foreach($r as $incFolder => $includes) 59 | { 60 | // README.md for example 61 | if (!is_array($includes)) continue; 62 | 63 | // target directory to store "includes" 64 | $includeTargetDir = $CONFIG['target']['includes'] . '/' . $incFolder; 65 | 66 | // make sure the target directory exists 67 | if (!file_exists($includeTargetDir)) { 68 | if (!mkdir($includeTargetDir)) { 69 | die('Could not create target directory: ' . $includeTargetDir); 70 | } 71 | } 72 | 73 | // render includes 74 | foreach($includes as $incFilename) 75 | { 76 | if ($incFilename == '.gitignore') { 77 | continue; 78 | } 79 | 80 | ob_start(); 81 | 82 | // do the magic 83 | nginx_bakery_render_include($incFolder . '/' .$incFilename); 84 | 85 | // get output buffer and save it as "include" config file 86 | $incTarget = $includeTargetDir . '/' . $incFilename; 87 | file_put_contents($incTarget, ob_get_clean()); 88 | nginx_bakery_log("Rendered include: " . $incFolder . '/' .$incFilename); 89 | } 90 | } 91 | 92 | // ==================================================================== 93 | // generate server configs 94 | foreach($SITES as $sitename => $siteServers) 95 | { 96 | ob_start(); 97 | 98 | // do the magix 99 | nginx_bakery_render_site($sitename, $siteServers); 100 | 101 | // get output buffer and save it as "server" config file 102 | $tplTarget = $CONFIG['target']['sites'] . '/' . $sitename; 103 | file_put_contents($tplTarget, ob_get_clean()); 104 | nginx_bakery_log("Rendered config [$sitename] to: " . $tplTarget); 105 | } 106 | 107 | echo NXB_EOL . NXB_EOL; 108 | 109 | // ==================================================================== 110 | // Script stuff ends here - functions follow 111 | // ==================================================================== 112 | 113 | function nginx_bakery_log($msg) 114 | { 115 | if (NXB_VERBOSE) { 116 | echo NXB_EOL . $msg; 117 | } 118 | } 119 | 120 | /** 121 | * Render a site with all its servers. 122 | * 123 | * @param $sitename 124 | * @param $siteServers 125 | * @throws Exception 126 | */ 127 | function nginx_bakery_render_site($sitename, $siteServers) 128 | { 129 | global $CONFIG; 130 | 131 | foreach($siteServers as $server) 132 | { 133 | if (!isset($server['recipe']) && !isset($server['cookbook'])) { 134 | throw new Exception('Site '.$sitename.' needs either a "cookbook" or a "recipe"'); 135 | } 136 | 137 | // recipe handling 138 | if (isset($server['recipe'])) 139 | { 140 | if (!is_array($server['recipe'])) { 141 | $server['recipe'] = array($server['recipe']); 142 | } 143 | 144 | foreach($server['recipe'] as $serverType) { 145 | nginx_bakery_render_type($sitename, $serverType, $server['config']); 146 | } 147 | } 148 | // cookbooks are handled with recursion 149 | else { 150 | // allow people to overrides single entries in cookbooks 151 | if (!isset($server['overrides'])) { 152 | $server['overrides'] = array(); 153 | } 154 | 155 | $cookbookConfig = nginx_bakery_config_from_cookbook($server['cookbook'], $server['config'], $server['overrides']); 156 | nginx_bakery_render_site($sitename, $cookbookConfig); 157 | return; 158 | } 159 | } 160 | } 161 | 162 | /** 163 | * Return a full set of server configs for a cookbook and a config. 164 | * 165 | * @param $cookbook 166 | * @param array $server 167 | * @return array 168 | * @throws Exception 169 | */ 170 | function nginx_bakery_config_from_cookbook($cookbook, array $server, array $overrides) 171 | { 172 | global $CONFIG; 173 | 174 | $fileName = null; 175 | 176 | if (isset($CONFIG['cookbooks'][$cookbook])) { 177 | $fileName = $CONFIG['cookbooks'][$cookbook]; 178 | } else if (file_exists(__DIR__ . '/cookbooks/' . $cookbook . '.php')) { 179 | $fileName = 'cookbooks/' . $cookbook . '.php'; 180 | } else { 181 | $fileName = $cookbook; 182 | } 183 | 184 | if ($fileName === null || !file_exists(__DIR__ . '/' . $fileName)) { 185 | throw new Exception('Cookbook does not exist or file is missing:' . $cookbook); 186 | } 187 | 188 | $configBook = include __DIR__ . '/' . $fileName; 189 | 190 | // override the default cookbook values with the supplied configuration 191 | // TODO - find a more elegant way 192 | if (!empty($overrides)) { 193 | foreach($overrides as $k => $v) { 194 | if (isset($overrides[$k])) { 195 | $configBook[$k] = array_merge($configBook[$k], $overrides[$k]); 196 | } 197 | } 198 | } 199 | 200 | // dynamic replacer in the style %somekey% 201 | array_walk_recursive($configBook, function(&$item, $key) use ($server) { 202 | if (preg_match("/\%(.*)\%/", $item, $matches)) { 203 | if(isset($server[$matches[1]])) { 204 | $item = str_replace($matches[0], $server[$matches[1]], $item); 205 | } 206 | } 207 | }); 208 | 209 | return $configBook; 210 | } 211 | 212 | /** 213 | * Renders an nginx "include". 214 | * 215 | * $CONFIG can be used in the included server-recipe. 216 | * 217 | * @param $filename 218 | */ 219 | function nginx_bakery_render_include($filename) 220 | { 221 | // $CONFIG might be used within the included nginx-include 222 | global $CONFIG; 223 | 224 | if (!file_exists(NXB_INC . $filename)) { 225 | throw new Exception('Include does not exist: '.$filename); 226 | } 227 | 228 | echo NXB_EOL; 229 | include NXB_INC . $filename; 230 | echo NXB_EOL; 231 | } 232 | 233 | /** 234 | * Renders a server part. 235 | * 236 | * Both $BAKERY and $CONFIG can be used in the included server-recipe. 237 | * 238 | * @param $serverName 239 | * @param $type 240 | * @param array $BAKERY the configuration from the user "site" 241 | * @throws Exception 242 | */ 243 | function nginx_bakery_render_type($serverName, $type, array $BAKERY) 244 | { 245 | // $CONFIG might be used within the included "server recipe" 246 | global $CONFIG; 247 | 248 | if (!isset($CONFIG['server'][$type])) { 249 | throw new Exception('Server has no recipe: '. $serverName); 250 | } 251 | 252 | // inject the $serverName as new field "_project_key" 253 | $BAKERY['_project_key'] = $serverName; 254 | 255 | echo NXB_EOL; 256 | include $CONFIG['server'][$type]; 257 | echo NXB_EOL; 258 | } 259 | 260 | /** 261 | * Renders the contents within a "server". 262 | * 263 | * @param array $siteConfig 264 | * @throws Exception 265 | */ 266 | function nginx_bakery_render_server(array $siteConfig) 267 | { 268 | global $CONFIG; 269 | 270 | foreach($siteConfig as $configKey => $configValue) 271 | { 272 | switch ($configKey) { 273 | case 'listen': 274 | case 'server_name': 275 | case 'index': 276 | case 'root': 277 | echo NXB_TAB . $configKey . ' ' . $configValue . ';' . NXB_EOL; 278 | break; 279 | case 'nginx': 280 | foreach($configValue as $nginxKey => $nginxValue) { 281 | echo NXB_EOL . NXB_TAB . $nginxKey . ' ' . $nginxValue . ';'; 282 | } 283 | echo NXB_EOL; 284 | break; 285 | case 'includes': 286 | foreach($configValue as $incName) { 287 | nginx_bakery_render_include_tag($incName); 288 | } 289 | break; 290 | case '_project_key': 291 | break; 292 | default: 293 | throw new Exception('Unsupported configuration key: ' . $configKey); 294 | break; 295 | } 296 | } 297 | echo NXB_EOL; 298 | } 299 | 300 | function nginx_bakery_render_include_tag($name) 301 | { 302 | global $CONFIG; 303 | 304 | if (isset($CONFIG['includes'][$name])) { 305 | $name = $CONFIG['includes'][$name]; 306 | } 307 | echo NXB_EOL . NXB_TAB . 'include' . ' ' . $name . ';'; 308 | } 309 | 310 | -------------------------------------------------------------------------------- /certificates/README.md: -------------------------------------------------------------------------------- 1 | Certificates 2 | ============ 3 | 4 | This directory could hold all your certificates. 5 | 6 | To generate a certificate, please refer to http://wiki.nginx.org/HttpSslModule#Generate_Certificates 7 | or follow these steps (one by one, as you might have to enter some information): 8 | 9 | ``` 10 | cd /opt/nginx-bakery/certificates 11 | openssl genrsa -out server.key 2048 12 | openssl req -new -key server.key -out server.csr 13 | openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt 14 | ``` 15 | 16 | Attention 17 | ========= 18 | Be warned, that the include `includes/general/ssl.conf` uses this exact name and location. 19 | If you do not want the filename "server" or want to use another location (recommended), 20 | change "config.php" accordingly and regenerate the files. 21 | 22 | Warning! 23 | ======== 24 | Make sure that this directory and the files within have proper permissions, 25 | you do not (really never!) want a script to be able to read or overwrite the certificates. 26 | 27 | Or even worse: pointing a default domain to /var/www/ with activated "directory listings"... 28 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | array( 13 | // directory where parsed includes will be stored 14 | 'includes' => __DIR__ . '/nginx/includes', 15 | // directory where generated server configs will be stored 16 | 'sites' => __DIR__ . '/nginx/sites-enabled', 17 | // external files being included while parsing can be defined by a key-value mapping of source => target directory 18 | 'externals' => array() 19 | ), 20 | 'options' => array( 21 | 'php_fastcgi_pass' => 'unix:/run/php/php7.1-fpm.sock', 22 | 'php_open_basedir' => '/tmp/', 23 | 'access_log' => '/dev/null', 24 | ), 25 | // full path to your certificates, change them to your needs and check certificates/README.md 26 | 'certificates' => array( 27 | // we look for "default" only if no side specific certificate can be found 28 | 'default' => array( 29 | 'crt' => __DIR__ . '/certificates/server.crt', 30 | 'key' => __DIR__ . '/certificates/server.key' 31 | ), 32 | /* 33 | // e.g. the site 'example.org' would look like: 34 | 'example.org' => array( 35 | 'crt' => __DIR__ . '/certificates/example_org.crt', 36 | 'key' => __DIR__ . '/certificates/example_org.key' 37 | ), 38 | */ 39 | ), 40 | // a set of server definitions (one represents a site/domain) 41 | // cookbooks can be reused across several domains, which only vary in a couple of variables 42 | // this is a simple name-to-file mapping, to allow placing cookbooks outside the default directory "cookbooks/" 43 | 'cookbooks' => array( 44 | 'bigace-v2' => 'cookbooks/bigace-v2.php', 45 | 'bigace-v3' => 'cookbooks/bigace-v3.php', 46 | 'wordpress' => 'cookbooks/wordpress.php', 47 | 'php-fpm' => 'cookbooks/php-fpm.php', 48 | 'cdn' => 'cookbooks/cdn.php', 49 | 'jekyll' => 'cookbooks/jekyll-https.php', 50 | ), 51 | // server recipes, each one represents a server entry in your nginx config 52 | // this is a simple name-to-file mapping 53 | 'server' => array( 54 | 'http-default' => 'recipes/80-default.conf', 55 | 'https-default' => 'recipes/443-default.conf', 56 | 'http-redirect_server' => 'recipes/80-redirect_server.conf', 57 | 'https-redirect_server' => 'recipes/443-redirect_server.conf', 58 | 'http-redirect_static' => 'recipes/80-redirect_static.conf', 59 | 'https-redirect_static' => 'recipes/443-redirect_static.conf', 60 | 'plaintext' => 'recipes/plaintext.conf' 61 | ), 62 | // nginx includes - re-usable includes which allow to access variables when being "baked" 63 | // note: they are generated once and afterwards all values are static 64 | // this is a simple name-to-file mapping to be used in 65 | 'includes' => array( 66 | '404' => 'includes/error/404.conf', 67 | '50x' => 'includes/error/50x.conf', 68 | 'cache-assets' => 'includes/general/cache-assets.conf', 69 | 'htaccess' => 'includes/general/deny-htaccess.conf', 70 | 'favicon' => 'includes/general/favicon.conf', 71 | 'php-fpm' => 'includes/general/php-fpm.conf', 72 | 'robots' => 'includes/general/robots.conf', 73 | 'empty' => 'includes/general/empty.conf', 74 | 'no-logs' => 'includes/general/no-logs.conf', 75 | 'hide-headers' => 'includes/general/hide-headers.conf', 76 | 'bigace-v2' => 'includes/software/bigace-v2.conf', 77 | 'bigace-v3' => 'includes/software/bigace-v3.conf', 78 | 'dokuwiki' => 'includes/software/dokuwiki.conf', 79 | 'piwik-tracking' => 'includes/software/piwik-tracking.conf', 80 | 'smf-v1' => 'includes/software/smf-v1.conf', 81 | 'smf-v2-prettyurls' => 'includes/software/smf-v2-prettyurls.conf', 82 | 'wordpress' => 'includes/wordpress/common.conf', 83 | 'wordpress-phpfpm' => 'includes/wordpress/php-fpm.conf', 84 | 'wordpress-hide' => 'includes/wordpress/hide-login.conf', 85 | 'wordpress-301-ssl' => 'includes/wordpress/redirect-ssl.conf', 86 | 'wordpress-admin' => 'includes/wordpress/administration.conf', 87 | 'kimai' => 'includes/software/kimai.conf', 88 | 'symfony4' => 'includes/software/symfony4.conf', 89 | 'yourls' => 'includes/software/yourls.conf', 90 | 'jekyll' => 'includes/software/jekyll.conf', 91 | 'freshrss' => 'includes/software/freshrss.conf', 92 | 'ssl' => 'includes/general/ssl.conf', 93 | 'security' => 'includes/general/security.conf', 94 | ), 95 | ); -------------------------------------------------------------------------------- /cookbooks/bigace-v2.php: -------------------------------------------------------------------------------- 1 | 'http-redirect_server', 13 | 'config' => array( 14 | 'server_name' => '%redirect%', 15 | 'target' => '%server_name%' 16 | ), 17 | ), 18 | array( 19 | 'recipe' => 'https-redirect_server', 20 | 'config' => array( 21 | 'server_name' => '%redirect%', 22 | 'target' => '%server_name%' 23 | ), 24 | ), 25 | array( 26 | 'recipe' => array('http-default', 'https-default'), 27 | 'config' => array( 28 | 'server_name' => '%server_name%', 29 | 'root' => '%root%', 30 | 'index' => 'index.php', 31 | 'includes' => array( 32 | '%include%', 'favicon', 'bigace-v2', 'piwik-tracking', 'htaccess' 33 | ) 34 | ), 35 | ), 36 | ); -------------------------------------------------------------------------------- /cookbooks/bigace-v3.php: -------------------------------------------------------------------------------- 1 | 'http-redirect_server', 13 | 'config' => array( 14 | 'server_name' => '%redirect%', 15 | 'target' => '%server_name%' 16 | ), 17 | ), 18 | array( 19 | 'recipe' => 'https-redirect_server', 20 | 'config' => array( 21 | 'server_name' => '%redirect%', 22 | 'target' => '%server_name%' 23 | ), 24 | ), 25 | array( 26 | 'recipe' => array('http-default', 'https-default'), 27 | 'config' => array( 28 | 'server_name' => '%server_name%', 29 | 'root' => '%root%', 30 | 'index' => 'index.php', 31 | 'includes' => array( 32 | '%include%', 'favicon', 'bigace-v3', 'piwik-tracking', 'htaccess' 33 | ) 34 | ), 35 | ), 36 | ); -------------------------------------------------------------------------------- /cookbooks/cdn.php: -------------------------------------------------------------------------------- 1 | array('http-default', 'https-default'), 12 | 'config' => array( 13 | 'server_name' => '%server_name%', 14 | 'root' => '%root%', 15 | 'index' => 'index.php index.html', 16 | 'includes' => array( 17 | '%include%', 'favicon', 'robots', 'htaccess', 'cache-assets' 18 | ) 19 | ), 20 | ), 21 | ); -------------------------------------------------------------------------------- /cookbooks/jekyll-https.php: -------------------------------------------------------------------------------- 1 | 'http-redirect_server', 15 | 'config' => array( 16 | 'server_name' => array('%redirect%', '%server_name%'), 17 | 'target' => 'https://%server_name%' 18 | ), 19 | ), 20 | array( 21 | 'recipe' => 'https-redirect_server', 22 | 'config' => array( 23 | 'server_name' => '%redirect%', 24 | 'target' => '%server_name%' 25 | ), 26 | ), 27 | array( 28 | 'recipe' => array('https-default'), 29 | 'config' => array( 30 | 'server_name' => '%server_name%', 31 | 'root' => '%root%', 32 | 'includes' => array( 33 | '%include_ssl%', 'no-logs', 'htaccess', 'jekyll', 'favicon', 'cache-assets', 'hide-headers' 34 | ) 35 | ), 36 | ), 37 | ); -------------------------------------------------------------------------------- /cookbooks/php-fpm.php: -------------------------------------------------------------------------------- 1 | 'http-redirect_server', 13 | 'config' => array( 14 | 'server_name' => '%redirect%', 15 | 'target' => '%server_name%' 16 | ), 17 | ), 18 | array( 19 | 'recipe' => 'https-redirect_server', 20 | 'config' => array( 21 | 'server_name' => '%redirect%', 22 | 'target' => '%server_name%' 23 | ), 24 | ), 25 | array( 26 | 'recipe' => array('http-default', 'https-default'), 27 | 'config' => array( 28 | 'server_name' => '%server_name%', 29 | 'root' => '%root%', 30 | 'index' => 'index.php', 31 | 'includes' => array( 32 | '%include%', 'favicon', 'php-fpm', 'robots', 'cache-assets', 'htaccess' 33 | ) 34 | ), 35 | ), 36 | ); -------------------------------------------------------------------------------- /cookbooks/wordpress-https.php: -------------------------------------------------------------------------------- 1 | 'https-redirect_server', 15 | 'config' => array( 16 | 'server_name' => '%redirect%', 17 | 'target' => '%server_name%' 18 | ), 19 | ), 20 | array( 21 | 'recipe' => array('https-default'), 22 | 'config' => array( 23 | 'server_name' => '%server_name%', 24 | 'root' => '%root%', 25 | 'index' => 'index.php', 26 | 'includes' => array( 27 | '%include_ssl%', 'no-logs', 'favicon', 'wordpress', 'wordpress-phpfpm', 'wordpress-admin', 'cache-assets', 'htaccess', 'hide-headers' 28 | ) 29 | ), 30 | ), 31 | ); -------------------------------------------------------------------------------- /cookbooks/wordpress.php: -------------------------------------------------------------------------------- 1 | 'http-redirect_server', 18 | 'config' => array( 19 | 'server_name' => '%redirect%', 20 | 'target' => '%server_name%' 21 | ), 22 | ), 23 | array( 24 | 'recipe' => 'https-redirect_server', 25 | 'config' => array( 26 | 'server_name' => '%redirect%', 27 | 'target' => '%server_name%' 28 | ), 29 | ), 30 | array( 31 | 'recipe' => array('http-default'), 32 | 'config' => array( 33 | 'server_name' => '%server_name%', 34 | 'root' => '%root%', 35 | 'index' => 'index.php', 36 | 'includes' => array( 37 | // optional use wordpress-301-ssl instead of wordpress-hide 38 | '%include%', 'favicon', 'wordpress', 'wordpress-phpfpm', 'wordpress-hide', 'cache-assets', 'htaccess', 'hide-headers' 39 | ) 40 | ), 41 | ), 42 | array( 43 | 'recipe' => array('https-default'), 44 | 'config' => array( 45 | 'server_name' => '%server_name%', 46 | 'root' => '%root%', 47 | 'index' => 'index.php', 48 | 'includes' => array( 49 | '%include_ssl%', 'favicon', 'wordpress', 'wordpress-phpfpm', 'wordpress-admin', 'cache-assets', 'htaccess', 'hide-headers' 50 | ) 51 | ), 52 | ), 53 | ); -------------------------------------------------------------------------------- /default_site/index.html: -------------------------------------------------------------------------------- 1 |
The requested page could not be found - sorry!
3 | 4 | -------------------------------------------------------------------------------- /error_pages/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Sorry, the page you are looking for could not be found.
16 | Please try again later.
If you are the system administrator of this resource then you should check 18 | the error log for details.
19 |Faithfully yours, System Administrator.
20 | 21 | 22 | -------------------------------------------------------------------------------- /error_pages/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Sorry, the page you are looking for is currently unavailable.
16 | Please try again later.
If you are the system administrator of this resource then you should check 18 | the error log for details.
19 |Faithfully yours, System Administrator.
20 | 21 | 22 | -------------------------------------------------------------------------------- /ingredients/README.md: -------------------------------------------------------------------------------- 1 | bakery includes 2 | =============== 3 | 4 | This directory includes all the **ingredients** that make up a good **recipe** within the **bakery**: 5 | 6 | - error (ingredients for error handling) 7 | - general (general feature ingredients) 8 | - sites (your personal site ingredients) 9 | - software (ingredients for different software products) 10 | -------------------------------------------------------------------------------- /ingredients/error/404.conf: -------------------------------------------------------------------------------- 1 | error_page 404 /404.html; 2 | location = /404.html { 3 | root /opt/nginx-bakery/error_pages; 4 | } 5 | -------------------------------------------------------------------------------- /ingredients/error/50x.conf: -------------------------------------------------------------------------------- 1 | error_page 500 502 503 504 /50x.html; 2 | location = /50x.html { 3 | root /opt/nginx-bakery/error_pages; 4 | } 5 | -------------------------------------------------------------------------------- /ingredients/general/cache-assets.conf: -------------------------------------------------------------------------------- 1 | 2 | location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { 3 | access_log /dev/null; 4 | expires max; 5 | log_not_found off; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ingredients/general/deny-htaccess.conf: -------------------------------------------------------------------------------- 1 | 2 | location ~ /\.ht { 3 | deny all; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /ingredients/general/empty.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinpapst/nginx-bakery/ca5220148129dc707730cfbce3cd31f7c229fe8b/ingredients/general/empty.conf -------------------------------------------------------------------------------- /ingredients/general/favicon.conf: -------------------------------------------------------------------------------- 1 | 2 | location = /favicon.ico { 3 | log_not_found off; 4 | access_log /dev/null; 5 | } 6 | -------------------------------------------------------------------------------- /ingredients/general/hide-headers.conf: -------------------------------------------------------------------------------- 1 | ### Security (through obscurity) - https://en.wikipedia.org/wiki/Security_through_obscurity 2 | # To hide nginx version 3 | server_tokens off; 4 | 5 | # To hide PHP version and other related fastcgi headers 6 | fastcgi_hide_header X-Powered-By; 7 | fastcgi_hide_header X-Pingback; 8 | fastcgi_hide_header Link; 9 | 10 | proxy_hide_header X-Powered-By; 11 | proxy_hide_header X-Pingback; 12 | proxy_hide_header X-Link; 13 | 14 | # sudo apt-get install nginx-extras 15 | more_clear_headers Server; 16 | -------------------------------------------------------------------------------- /ingredients/general/no-logs.conf: -------------------------------------------------------------------------------- 1 | log_not_found off; 2 | access_log /dev/null; 3 | error_log /dev/null; 4 | -------------------------------------------------------------------------------- /ingredients/general/php-fpm.conf: -------------------------------------------------------------------------------- 1 | 2 | location / { 3 | # This is cool because no php is touched for static content. 4 | # include the "?$args" part so non-default permalinks doesn't break when using query string 5 | try_files $uri $uri/ /index.php?$args; 6 | } 7 | 8 | location ~ \.php$ { 9 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 10 | fastcgi_pass ; 11 | fastcgi_index index.php; 12 | include fastcgi_params; 13 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:"; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /ingredients/general/robots.conf: -------------------------------------------------------------------------------- 1 | 2 | location = /robots.txt { 3 | allow all; 4 | log_not_found off; 5 | access_log /dev/null; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ingredients/general/security.conf: -------------------------------------------------------------------------------- 1 | # @see https://observatory.mozilla.org/analyze.html?host=www.example.com 2 | # @see https://infosec.mozilla.org/guidelines/web_security#contributejson 3 | 4 | # Block site from being framed with X-Frame-Options and CSP 5 | add_header 'X-Frame-Options' 'SAMEORIGIN'; 6 | 7 | # Disable referrers for browsers that don't support strict-origin-when-cross-origin 8 | # Uses strict-origin-when-cross-origin for browsers that do 9 | add_header 'Referrer-Policy' 'no-referrer, strict-origin-when-cross-origin'; 10 | 11 | # Block pages from loading when they detect reflected XSS attacks 12 | add_header "X-XSS-Protection" "1; mode=block"; 13 | 14 | # Block site from being framed with X-Frame-Options and CSP 15 | #add_header "Content-Security-Policy" "frame-ancestors 'none'; object-src 'self'; base-uri 'none'; plugin-types 'application/pdf';"; 16 | #add_header "Content-Security-Policy" "default-src https: data: 'unsafe-eval' 'unsafe-inline';"; 17 | 18 | # Prevent browsers from incorrectly detecting non-scripts as scripts 19 | add_header "X-Content-Type-Options" "nosniff"; -------------------------------------------------------------------------------- /ingredients/general/ssl.conf: -------------------------------------------------------------------------------- 1 | # Only connect to this site and subdomains via HTTPS for the next year and also include in the preload list 2 | #Strict-Transport-Security: max-age=31536000; includeSubDomains; preload 3 | add_header 'Strict-Transport-Security' 'max-age=31536000' always; -------------------------------------------------------------------------------- /ingredients/software/bigace-v2.conf: -------------------------------------------------------------------------------- 1 | location / { 2 | # include the "?$args" part so non-default permalinks doesn't break when using query string 3 | try_files $uri $uri/ /public/index.php?id=$uri&$args; 4 | } 5 | 6 | location ^~ /bigace { 7 | rewrite ^/bigace/(.*)/(.*)/(.*) /public/index.php?cmd=$1&id=$2&name=$3&$query_string last; 8 | } 9 | 10 | location ~ \.php$ { 11 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 12 | fastcgi_intercept_errors on; 13 | fastcgi_pass ; 14 | fastcgi_index index.php; 15 | include fastcgi_params; 16 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:"; 17 | } -------------------------------------------------------------------------------- /ingredients/software/bigace-v3.conf: -------------------------------------------------------------------------------- 1 | location / { 2 | # include the "?$args" part so non-default permalinks doesn't break when using query string 3 | try_files $uri $uri/ /index.php?id=$uri&$args; 4 | } 5 | 6 | location ~ \.php$ { 7 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 8 | fastcgi_intercept_errors on; 9 | fastcgi_pass ; 10 | fastcgi_index index.php; 11 | include fastcgi_params; 12 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/../:$document_root:"; 13 | } 14 | -------------------------------------------------------------------------------- /ingredients/software/dokuwiki.conf: -------------------------------------------------------------------------------- 1 | location / { 2 | index doku.php; 3 | try_files $uri $uri/ @dokuwiki; 4 | } 5 | 6 | location @dokuwiki { 7 | rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last; 8 | rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last; 9 | rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last; 10 | rewrite ^/(.*) /doku.php?id=$1 last; 11 | } 12 | 13 | location ~ /(data|conf|bin|inc)/ { 14 | deny all; 15 | } 16 | 17 | location ~ \.php$ { 18 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 19 | fastcgi_pass ; 20 | fastcgi_index index.php; 21 | include fastcgi_params; 22 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:"; 23 | } 24 | -------------------------------------------------------------------------------- /ingredients/software/freshrss.conf: -------------------------------------------------------------------------------- 1 | location ~ ^.+?\.php(/.*)?$ { 2 | fastcgi_pass ; 3 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 4 | # By default, the variable PATH_INFO is not set under PHP-FPM 5 | # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var! 6 | fastcgi_param PATH_INFO $fastcgi_path_info; 7 | include fastcgi_params; 8 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 9 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/..:/$document_root:"; 10 | } 11 | 12 | location / { 13 | try_files $uri $uri/ index.php; 14 | } 15 | 16 | # return 404 for all other php files not matching the front controller 17 | # this prevents access to other php files you don't want to be accessible. 18 | location ~ \.php$ { 19 | return 404; 20 | } 21 | -------------------------------------------------------------------------------- /ingredients/software/jekyll.conf: -------------------------------------------------------------------------------- 1 | error_page 404 /404.html; 2 | location = /404.html { 3 | log_not_found off; 4 | access_log /dev/null; 5 | internal; 6 | } 7 | 8 | location = /xmlrpc.php { 9 | log_not_found off; 10 | access_log /dev/null; 11 | } 12 | 13 | location = /wp-login.php { 14 | log_not_found off; 15 | access_log /dev/null; 16 | } 17 | -------------------------------------------------------------------------------- /ingredients/software/kimai.conf: -------------------------------------------------------------------------------- 1 | # Deny access to any files with a .php extension in the includes directory 2 | location ~* /includes/.*\.php$ { 3 | deny all; 4 | } 5 | -------------------------------------------------------------------------------- /ingredients/software/piwik-tracking.conf: -------------------------------------------------------------------------------- 1 | location ^~ /piwik/ { 2 | 3 | alias /var/www/piwik/; 4 | 5 | location =/piwik/piwik.php { 6 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 7 | fastcgi_pass ; 8 | include fastcgi_params; 9 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=/var/www/piwik/:$document_root:"; 10 | } 11 | 12 | location =/piwik/index.php { 13 | if ($arg_module != "CoreAdminHome") { 14 | return 404; 15 | } 16 | if ($arg_action != "optOut") { 17 | return 404; 18 | } 19 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 20 | fastcgi_pass ; 21 | include fastcgi_params; 22 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=/var/www/piwik/:$document_root:"; 23 | } 24 | 25 | 26 | location =/piwik/piwik.js { 27 | try_files /piwik.js =204; 28 | } 29 | 30 | # all other files are not allowed 31 | location ~* ^.+$ { 32 | return 404; 33 | } 34 | } -------------------------------------------------------------------------------- /ingredients/software/smf-v1.conf: -------------------------------------------------------------------------------- 1 | location ~ \.php$ { 2 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 3 | fastcgi_pass ; 4 | fastcgi_index index.php; 5 | include fastcgi_params; 6 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:"; 7 | } 8 | -------------------------------------------------------------------------------- /ingredients/software/smf-v2-prettyurls.conf: -------------------------------------------------------------------------------- 1 | location / { 2 | try_files $uri $uri/ @rewrite; 3 | } 4 | 5 | location @rewrite { 6 | # Rules for: actions 7 | rewrite ^/(activate|admin|ads|announce|attachapprove|ban|boardrecount|buddy|calendar|clock)/?$ "/index.php?pretty;action=$1" last; 8 | rewrite ^/(collapse|convertentities|coppa|credits|deletemsg|detailedversion|display|dlattach|editpoll|editpoll2)/?$ "/index.php?pretty;action=$1" last; 9 | rewrite ^/(emailuser|featuresettings|findmember|groups|help|helpadmin|im|jseditor|jsmodify)/?$ "/index.php?pretty;action=$1" last; 10 | rewrite ^/(jsoption|lock|lockvoting|login|login2|logout|manageboards|managecalendar|managesearch|manageattachments|maintain|markasread|mascot)/?$ "/index.php?pretty;action=$1" last; 11 | rewrite ^/(membergroups|mergetopics|mlist|moderate|modifycat|modifykarma|movetopic|movetopic2|news|notify)/?$ "/index.php?pretty;action=$1" last; 12 | rewrite ^/(notifyboard|optimizetables|openidreturn|packages|permissions|pm|post|postsettings|post2|printpage|profile|quotefast)/?$ "/index.php?pretty;action=$1" last; 13 | rewrite ^/(quickmod|quickmod2|recent|regcenter|register|register2|reminder|removepoll|removetopic2)/?$ "/index.php?pretty;action=$1" last; 14 | rewrite ^/(repairboards|reporttm|requestmembers|restoretopic|reports|search|search2|sendtopic|serversettings|smileys|smstats|suggest)/?$ "/index.php?pretty;action=$1" last; 15 | rewrite ^/(spellcheck|splittopics|stats|sticky|theme|trackip|about:mozilla|about:unknown)/?$ "/index.php?pretty;action=$1" last; 16 | rewrite ^/(unread|unreadreplies|verificationcode|viewErrorLog|viewmembers|viewprofile|vote|viewquery|viewsmfile|who)/?$ "/index.php?pretty;action=$1" last; 17 | rewrite ^/(\.xml|xmlhttp)/?$ "/index.php?pretty;action=$1" last; 18 | 19 | # Rules for: boards & Topics 20 | rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/?$ "/index.php?pretty;board=$1.0" last; 21 | rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([0-9]*)/?$ "/index.php?pretty;board=$1.$2" last; 22 | rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([-_!~*'()$a-zA-Z0-9]+)/?$ "/index.php?pretty;board=$1;topic=$2.0" last; 23 | rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([-_!~*'()$a-zA-Z0-9]+)/([0-9]*|msg[0-9]*|new)/?$ "/index.php?pretty;board=$1;topic=$2.$3" last; 24 | } 25 | 26 | location ~ \.php$ { 27 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 28 | fastcgi_pass ; 29 | fastcgi_index index.php; 30 | include fastcgi_params; 31 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:"; 32 | } 33 | -------------------------------------------------------------------------------- /ingredients/software/symfony4.conf: -------------------------------------------------------------------------------- 1 | location / { 2 | # try to serve file directly, fallback to index.php 3 | try_files $uri /index.php$is_args$args; 4 | } 5 | 6 | location ~ ^/index\.php(/|$) { 7 | fastcgi_pass ; 8 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 9 | include fastcgi_params; 10 | fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/..:/$document_root:"; 11 | 12 | # optionally set the value of the environment variables used in the application 13 | # fastcgi_param APP_ENV prod; 14 | # fastcgi_param APP_SECRET