diff --git a/0.-Overview.md b/0.-Overview.md index 5d08b7b..83f4c9c 100644 --- a/0.-Overview.md +++ b/0.-Overview.md @@ -1 +1,9 @@ -Welcome to the Wiki. \ No newline at end of file +# ab-nginx + +The goal of this container is to make deploying NGINX simpler in a containerized situations by creating a more logical file structure that lends itself to common sense bind-mounts in a variety of situations. In addition, SSL management has been made dead simple and secure by default using recommended configuration templates from Mozilla. Most configurations are automatically enabled based on what has been bound to the container or on simple environment variable values. Finally, the container has a health-check which is mysteriously missing from the official images. + +The next few pages of this wiki will go in-depth into how you can deploy and use this container. I hate when things aren’t documented, so it’s my goal not to make that mistake here. For those of you that are already familiar with docker, and NGINX in particular, the quick-start is probably all you need. Those of you newer to containerized deployment of NGINX or who are just curious about how things work, the rest of this wiki is for you! + +I hope this container makes you life a little easier. As always, if you have any suggestions or find any bugs, please let me know by filing an issue! Lastly, please be aware that I am **NOT** in any way affiliated with NGINX. If you find something wrong with this container, please do *not* bother them, just give me a shout. + +Have fun! \ No newline at end of file diff --git a/1.-Quick-start.md b/1.-Quick-start.md index 5d08b7b..f90b91a 100644 --- a/1.-Quick-start.md +++ b/1.-Quick-start.md @@ -1 +1,174 @@ -Welcome to the Wiki. \ No newline at end of file +# Quick-start + +This section is meant primarily for those of you familiar with docker, NGINX and who have some experience working with containerized instances of NGINX in the past. If stuff here doesn’t really make sense to you, read it anyways and then go on to the other pages of the wiki and things will become clear. I’ve tried to make the container simpler than the official image, so hopefully I should be able to explain why that’s the case :stuck_out_tongue_closed_eyes: + +## Contents + +[Basic file structure](#basic-file-structure) +[Running the container](#running-the-container) + [Proper file extensions](#proper-file-extensions) +[Server-blocks](#server-blocks) +[SSL (briefly)](#ssl-briefly) +[Environment variables](#environment-variables) +[Troubleshooting](#troubleshooting) +[Next steps](#next-steps) + +## Basic file structure + +In terms of file structure, the container is divided into two main parts: content and configuration. + +- **ALL** content should be mounted to `/usr/share/nginx/html` in the container. You can use bind-mounts (better) or volume-mounts. Bind-mounts, of course, allow you to edit easily on the host machine and have those changes displayed by the container. +- **ALL** configuration resides in `/etc/nginx` and its subdirectories: + - `/etc/nginx/config`: HTTP-level configuration for things such as default headers, buffers, proxy-settings, SSL configuration, gzip, timeouts, etc. I strongly recommend splitting your configuration into separate files organized by purpose/theme and placing them all in one directory. Then bind-mount that directory to this location in the container and they will be applied via the *nginx.conf* file. + - `/etc/nginx/sites`: Your server-blocks should be mounted here. Again, you can have just one configuration file or several, perhaps one for each service if you’re using this container as a reverse-proxy. By default, two files live in this directory. One is a non-secured server running on port 80. The other is a secured server running on port 443 with an automatic redirect from port 80. Both server configurations serve whatever they can find in the webroot as static content. Nothing fancy, they just work and have common-sense configurations. The secured version will be automatically enabled by the container if certificates have been mounted. If you mount your own you server-blocks, you can do so in-addition to these default blocks or you can overwrite the entire directory with your own configurations. +- In most cases, these are the only directories you need to worry about. +- More details can be found on the next page: File-structure. + +## Running the container + +It’s not a bad idea to just run the container quickly to make sure everything works and you can quickly take a look at the default set up for yourself. That really is the easiest way to see how it all works. + +1. Run in shell-mode, fully default setup, to browse the container layout. + + ```bash + docker run -it --rm asifbacchus/ab-nginx:latest /bin/sh + ``` + + This will launch the container *without* launching NGINX. You can see the output from the setup script and you can browse the file structure for yourself. Check out the `/etc/nginx` directory and maybe have do a `cat /etc/nginx/nginx.conf`. + +2. Next, let’s run the container properly but in the foreground so we can easily terminate it. + + ```bash + docker run --rm -p 127.0.0.1:80:80 asifbacchus/ab-nginx:latest + ``` + + Open an in-private/incognito web browser session and open http://127.0.0.1. We are using a private session to avoid the browser cache. You should see a welcome page confirming that everything is working properly. Assuming that’s all good, close your browser and press `ctrl-c` in your terminal to terminate the container. + +3. If you have some web content (or want to make some quickly), go ahead and bind-mount into your new container to test it out. Remember, you just mounting your directory of content to `/usr/share/nginx/html`. + + ```bash + docker run --rm -p 127.0.0.1:80:80 \ + -v ~/myWebStuff:/usr/share/nginx/html \ + asifbacchus/ab-nginx:latest + ``` + + Now open your browser (again, recommending a private session) and try it out. Pretty easy right? If all you need is to display static content, then you’re done. You might want to skip ahead to the SSL sections to get that setup. + +4. In the same vein, if you have custom configurations (say, some headers you want to apply, etc.) then you simply put those *.conf* files in a directory and bind-mount it to `/etc/nginx/config`. Here’s what that looks like along with your content, and this time we’ll run it detached so it’s more realistic: + + ```bash + docker run -d --rm --name ab-nginx -p 127.0.0.1:80:80 \ + -v ~/myWebstuff:/usr/share/nginx/html \ + -v ~/myNginxConfigs:/etc/nginx/config:ro \ + asifbacchus/ab-nginx:latest + ``` + + With the exception of SSL settings, the container does NOT have any configurations defined and just uses the built-in NGINX default settings. That’s why it’s possible to apply your own. When you’re done testing it out, run type the following to stop the container. It will be auto-removed since we started it with the `–rm` flag. + + ```bash + docker stop ab-nginx + ``` + + As an additional note, you can also bind-mount your own *nginx.conf* if you’d like: + + ```bash + docker run -d --rm --name ab-nginx -p 127.0.0.1:80:80 \ + -v ~/myWebstuff:/usr/share/nginx/html \ + -v ~/myNginxConfigs:/etc/nginx/config:ro \ + -v ~/nginx.conf:/etc/nginx/nginx.conf:ro \ + asifbacchus/ab-nginx:latest + ``` + +### Proper file extensions + +**By default, the *nginx.conf* in this container will only include files with a *.conf* file extension!** This means you can easily disable a server-block file or configuration file just by renaming it something like *server.conf.disabled*. That way you don’t have to delete files when you’re testing out new configurations. Of course, you have to restart the container so the new file names are recognized and the configuration is updated. + +## Server-blocks + +Just like bind-mounting configuration files, you can also bind-mount server-blocks at `/etc/nginx/sites`. You can mount them individually (perhaps adding to the default blocks) or you can gather them in a directory and override the defaults altogether, all depending on what you want to accomplish. Here’s both examples: + +```bash +# run an additional service on port 8080 +docker run -d --name ab-nginx \ + -p 80:80 \ + -p 8080:8080 \ + -v ~/myWebStuff:/usr/share/nginx/html \ + -v ~/myWebApp:/usr/share/nginx/myApp \ + -v ~/myNginxServers/webapp.conf:/etc/nginx/sites/webapp.conf:ro \ + asifbacchus/ab-nginx:latest + +# only use your own server-blocks +docker run -d --name ab-nginx \ + -p 80:80 \ + -v ~/myWebStuff:/usr/share/nginx/html \ + -v ~/myNginxServers:/etc/nginx/sites:ro \ + asifbacchus/ab-nginx:latest +``` + +## SSL (briefly) + +The container will auto-configure itself for either TLS 1.2+1.3 or only TLS 1.3 assuming you have provided certificates in the correct location as follows: + +| file type | container-location | +| ------------------------------------------------------------ | -------------------- | +| Full-chain certificate
(certificate concatenated with intermediates and/or root CA) | /certs/fullchain.pem | +| Private key | /certs/privkey.pem | +| Certificate chain (intermediates concatenated with root CA) | /certs/chain.pem | +| DH Parameters file (NOT required for TLS 1.3-only mode) | /certs/dhparams.pem | + +If the container finds these files on start-up, it will enable the SSL server configuration automatically (assuming you have also provided your own server-blocks). In addition, there are two environment variables you can set related to SSL operations. + +| environment variable | description | default | +| -------------------- | ------------------------------------------------------------ | ------- | +| TLS13_ONLY | Only accepts TLS 1.3 connections. Do NOT set this if you need to support TLS 1.2 since the container will not fall back. Please note that TLS 1.2 *will* scale up to TLS 1.3 whenever possible, so that might be a safer choice if you’re not sure what to choose. | FALSE | +| HSTS | Enables an HSTS header to always be sent. The header is configured for an SSL required period of 6 months. So, please be sure about your SSL configuration before enabling this option! | FALSE | + +Here’s an example of bind-mounting everything and enabling the above two options. In this example, I’m assuming you gathered all your certificate files in one directory to make it easier. + +```bash +docker run -d --name ab-nginx --restart unless-stopped \ + -p 80:80 \ + -p 443:443 \ + -v ~/myWebStuff:/usr/share/nginx/html \ + -v ~/certs:/certs:ro \ + -e TLS13_ONLY=TRUE \ + -e HSTS=TRUE \ + -e SERVER_NAMES="domain.net www.domain.net" \ + asifbacchus/ab-nginx:latest +``` + +One thing to be aware of also: The container defaults to a server name of “-” which means ‘match anything’. This *will not* work with SSL obviously. Therefore, it’s critical you provide hostnames corresponding to your SSL certificate. That’s why the `SERVER_NAMES` environment variable is set above. + +If you want to configure the container to support Let’s Encrypt, please see the SSL page. + +## Environment variables + +Finally, you should take a second an familiarize yourself with the various options that can be set via environment variables passed at runtime. More details can be found on the environment variables page later in this wiki. Here’s a brief overview: + +| name | description | default | +| ------------ | ------------------------------------------------------------ | --------------------------- | +| TZ | Set the container time zone for proper logging. | Etc/UTC | +| SERVER_NAMES | Space-delimited list of hostnames/FQDNs to which NGINX should respond. This can be overridden via individual server blocks. Must be "enclosed in quotes". | "_" (this means "anything") | +| HTTP_PORT | Port on which HTTP connections should be accepted. If you set this, make sure you set your port mapping properly! For example, if you set this to 8080 then you need to specify `-p 8080:8080` or something like `-p 12.34.567.89:8080:8080`. | 80 | +| HTTPS_PORT | Port on which HTTPS connections should be accepted. If you set this, make sure you set your port mapping properly! For example, if you set this to 8443 then you need to specify `-p 8443:8443` or something like `-p 12.34.567.89:8443:8443`. | 443 | +| ACCESS_LOG | Turn on/off access logging. There is a default format specified in the container's *nginx.conf*, but you can override this via configuration files. | off | +| HSTS | Activate the HSTS header. Please be sure you know what this means and that your SSL configuration is correct before enabling! | FALSE | +| TLS13_ONLY | Activate the container's default TLS 1.3 configuration. This is a strict TLS 1.3 implementation and does *not* fall back to TLS 1.2. If you still need to support TLS 1.2, then leave this turned off. The TLS 1.2 configuration *does* upgrade to TLS 1.3 where possible. | FALSE | + +## Troubleshooting + +If you run into any issues, it’s a good idea to run the container in shell-mode and see how your configurations have been applied or if you accidentally mapped something in the wrong place. Remember, NGINX does *not* load in shell-mode. As a review, here’s how you’d do a full setup and start the shell: + +```bash +docker run -it --rm \ + -v ~/myWebStuff:/usr/share/nginx/html \ + -v ~/myNginxConfigs:/etc/nginx/config:ro \ + -v ~/myNginxServers:/etc/nginx/sites:ro \ + -v ~/certs:/certs:ro \ + -e TLS13_ONLY=TRUE \ + asifbacchus/ab-nginx:latest /bin/sh +``` + +## Next steps + +Well, I think that was a pretty solid overview. If anything is not clear or you want more details, please keep reading the appropriate sections of this wiki. I know I might have been overly detailed, but I figured it’s better than the opposite! As always, if you find any bugs, errors in the documentation or have any suggestions, just drop me a line in the issues. I hope you enjoy using this container! \ No newline at end of file diff --git a/2.-File-structure.md b/2.-File-structure.md index 5d08b7b..eaca641 100644 --- a/2.-File-structure.md +++ b/2.-File-structure.md @@ -1 +1,43 @@ -Welcome to the Wiki. \ No newline at end of file +# File structure + +One of my goals in building this container was to make the file structure intuitive. So, I think by seeing it, it will make sense right away. + +```text +/etc/nginx +├── config +│ └── **add configuration files here or replace the whole directory** +├── sites +│ ├── 05-test_nonsecured.conf +│ ├── 05-test_secured.conf.disabled +│ └── **add additional server blocks files or replace whole directory** +├── ssl-config +│ ├── mozIntermediate_ssl.conf.disabled +│ └── mozModern_ssl.conf.disabled + └── (SSL configuration – container auto-handles this) +├── errorpages.conf – (pre-configured fun error pages, you can override ) +├── health.conf – (health-check endpoint, best to not touch this) +├── nginx.conf – **main NGINX configuration file, replace if desired** +├── server_names.conf – (list of hostnames, updated via environment variable) +├── ssl_certs.conf – (container auto-manages this file too) +``` + +All the files/directories with descriptions \**in double stars** are designed to be replaced with bind-mounts at your discretion to customize the container. I’ll briefly summarize what each directory and file does in the following tables so you have a better idea whether you need to replace it or work with the provided defaults: + +| directory | description | +| ---------- | ------------------------------------------------------------ | +| config | Files here with a *.conf* extension will be read into the HTTP-context as configuration options. You can have as many or as few files here as you like. Remember, files with any extension other than *.conf* **will be ignored**. This directory is empty by default meaning that only NGINX defaults are applied for all settings. | +| sites | Files here with a *.conf* extension will be read into the SERVER-context (i.e. server-blocks). You can have as many or as few files here as you like. Remember, files with any extension other than *.conf* **will be ignored**. This directory has simple ‘serve all files’ server-blocks by default for both secure and insecure setups. | +| ssl-config | By default, this is the directory where NGINX will look for SSL configurations. If you change the default configuration, of course, this may not be the case anymore. If you want to container to continue automatically handling SSL, then leave this folder alone. The default configurations are those recommended by Mozilla for TLS 1.2 and TLS 1.3. | + +| file | description | +| -------------------------------------------- | ------------------------------------------------------------ | +| sites/05-test_nonsecured.conf | This is a simple server block that serves any files it finds in the webroot and its children. The server operates on port 80 as plain HTTP and, while primarily for testing purposes, is perfectly suited to serving simple static content in production. | +| sites/05-test_secured.conf.disabled | This is a simple server block that serves any files it finds in the webroot and its children. The server operates on port 443 using HTTPS and HTTP/2. While it’s primarily intended for testing purposes, it is perfectly suited to serving static pages securely in production. When the container detects SSL certificated mounted in the container, it removes the *.disabled* extension and thus, enables this file while renaming the insecure configuration to disable it. This configuration auto-redirects insecure HTTP connections to secure HTTPS ones. | +| ssl-config/mozIntermediate_ssl.conf.disabled | This file contains all default TLS 1.2+1.3 configuration settings as recommended by Mozilla. When the server detects mounted certificates and `TLS13_ONLY=FALSE`, this configuration will be activated (i.e. the *disabled* extension will be dropped). | +| ssl-config/mozModern_ssl.conf.disabled | This file contains all default TLS 1.3 configuration settings as recommended by Mozilla. When the server detects mounted certificates and `TLS13_ONLY=TRUE`, this configuration will be activated (i.e. the *disabled* extension will be dropped). Note: This configuration makes no provision for falling back to TLS 1.2! | +| errorpages.conf | The container integrates some fun error pages from another project of mine. This configuration snippet enables those pages. You may, of course, override it or integrate it in your server-blocks if you’d like. The project, for reference, is located [here](https://git.asifbacchus.app/asif/fun-errorpages). | +| health.conf | This configuration snippet enables NGINX’s internal statistics ‘stub-site’ restricted to the local host only. The container is configured to query this stats-site every 60s to determine if NGINX is serving pages and uses that information to determine if the container is healthy. You should leave this file alone. | +| nginx.conf | This is the main NGINX configuration file and is responsible for the overall operation of the server. It also integrates the `config` and `sites` directories along with `ssl-config` and other files mentioned above. While you can override this file, you should carefully examine it before doing so otherwise the container may not function correctly. In nearly all cases, it makes more sense to expand/override it using the `config` directory. | +| server_names.conf | This file is constructed using the `SERVER_NAMES` environment variable and is managed by the container. It is a shorthand for server-blocks that need to reference all names of the server such as for redirecting all traffic to HTTPS, etc. You shouldn’t ever need to touch this file. | +| ssl_certs.conf | This file points to the location of the certificates mounted in the container. It is hard-coded to the `/certs` directory. You should not need to change this file but you may want to ‘include’ it in your server-blocks. | + diff --git a/3.-Environment-variables.md b/3.-Environment-variables.md new file mode 100644 index 0000000..97ac39e --- /dev/null +++ b/3.-Environment-variables.md @@ -0,0 +1,39 @@ +# Environment variables + +Several key configuration options of this container can be easily managed at runtime by setting simple environment variables. To set them, pass them on the command line to the container using `-e VAR_NAME=VALUE` or via docker-compose in the `environment:` stanza. + +- [TZ](#TZ) +- [SERVER_NAMES](#server-names) +- [HTTP_PORT](#http-port) +- [HTTPS_PORT](#https-port) +- [ACCESS_LOG](#access-log) +- [HSTS](#hsts) +- [TLS13_ONLY](#tls13-only) + +## TZ + +This variable sets the container’s time zone information. It is formatted as per the IANA standard that Linux uses (Region/Locality). For example, I am in Alberta, Canada so I use `America/Edmonton` which is *Mountain Time*. A good list can be found on [wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). By default, this is set to Universal Coordinated Time (GMT or ‘Zulu’) which is `TZ=Etc/UTC`. + +## SERVER_NAMES + +Space-delimited list of hostnames to which NGINX should respond. This environment variable *must* be quoted (since it is space delimited) and most often is used to match SSL certificates. It is used to generate a list on the server which is used as a shorthand for global redirections. By default this is set to `SERVER_NAMES=“-”` which means ‘match anything’. While that is perfect for HTTP connections, it will obviously fail for HTTPS connections. Therefore, make sure you set this variable when you enable HTTPS! + +## HTTP_PORT + +Unsurprisingly, this is set to port 80 by default. If you need/want to use a different port, specify it here. For example, you could set `HTTP_PORT=8080`. If you change this port mapping, remember to also change it when invoking the container using the `-p` switch, like `-p 8080:8080` in our example. In most cases, you should not need to change this mapping since you can change it on the host instead such as `-p 8080:80`. + +## HTTPS_PORT + +Just as with the previous variable, it should not surprise you this is set to port 443 by default. Exactly as above, you can change as desired/required. Again, remember to update your `-p` invocation option to match this value, for example `-p 8443:8443 -e HTTPS_PORT 8443`. Also like above, it is often more sensible to just change the mapping on the host like `-p 8443:443`. + +## ACCESS_LOG + +This controls whether or not the access log is output to stdout (the container’s console). This variable can be set to either `ACCESS_LOG=ON` or `ACCESS_LOG=OFF`. The latter is the default for performance reasons. By default, if enabled, it uses the *combined* default format however, you can freely override this in your own *nginx.conf* or using a file in the `config` directory (better choice). I have included an example of such an override in the Mounts: configuration page of this wiki. + +## HSTS + +Assuming you are using the default configuration and/or allowing the container to manage your SSL set up, this will enable the HSTS header for all pages. The header sets a max-age of 6 months, meaning that browsers are told to accept only SSL (really TLS) connections for the next 6 months from your site(s). Because of this, be sure of your configuration before turning this option on! That being said, once your configuration is settled, you should *definitely* enable this option. Valid options are `HSTS=FALSE` and `HSTS=TRUE`. This setting is completely ignored if the container does not have certificates mounted. + +## TLS13_ONLY + +Assuming you are allowing the container to manage your SSL set up, this will activate the TLS 1.3-only configuration. In this mode, the server will *NOT* fall back to TLS 1.2 communication, so make sure this works in your environment. If this is left disabled (the default), the server will accept TLS 1.2 connections but will also accept TLS 1.3 connections where possible and whenever requested. The difference is that by enabling this, you are *forcing* TLS 1.3 connections, which is a great idea if your environment permits it. Valid options are `TLS13_ONLY=FALSE` and `TLS_ONLY=TRUE`. This setting is completely ignored if the container does not have certificates mounted. \ No newline at end of file diff --git a/3.-Mounts%3A-content-and-sites.md b/4.-Mounts%3A-content-and-sites.md similarity index 100% rename from 3.-Mounts%3A-content-and-sites.md rename to 4.-Mounts%3A-content-and-sites.md diff --git a/4.-Mounts%3A-configuration.md b/5.-Mounts%3A-configuration.md similarity index 100% rename from 4.-Mounts%3A-configuration.md rename to 5.-Mounts%3A-configuration.md diff --git a/5.-SSL.md b/6.-SSL.md similarity index 100% rename from 5.-SSL.md rename to 6.-SSL.md diff --git a/6.-Deployment-scenarios.md b/7.-Deployment-scenarios.md similarity index 100% rename from 6.-Deployment-scenarios.md rename to 7.-Deployment-scenarios.md diff --git a/7.-Helper-scripts.md b/8.-Helper-scripts.md similarity index 100% rename from 7.-Helper-scripts.md rename to 8.-Helper-scripts.md