CloudPi

Nginx for Redirects and Reverse Proxy

To make life easier for your end users, this step will configure the Nginx web server to take care of sending HTTP requests to HTTPS instead. Nginx will also take care of SSL offloading for any applications that do not support it or are tedious to configure.

By the end of this step, you will have:

Can I Skip It?

With some applications, like Portainer, it’s easy to install the SSL certificate directly. Others are more difficult, but it can be done. It’s really up to you to weigh the effort required for directly applying certificates with the time spent configuring Nginx for redirects and reverse proxies. Some applications are easy to reverse proxy and others take more time to configure.

Of course, you may have already chosen to just do HTTP and not even worry about encryption. If that’s the case, you may still be interested in using Nginx for redirection or you might choose to forego all of it.

Summary of Commands

  1. ansible-playbook pre-deploy.yml
  2. docker-compose up -d

Why Redirection and Reverse Proxy?

It’s easy to remember names, and not so easy to remember arbitrary numbers. And using a web URL like http://nextcloud.mypi.home is easier than remembering and typing the port number ever time, like this: http://mypi.home:8910. By deploying the Nginx web server, you can configure redirection, so http://nextcloud.mypi.home automatically sends the browser to http://mypi.home:8910. Or you can set up a reverse proxy, so https://nextcloud.mypi.home relays communications from the browser to http://mypi.home:8910, while also supplying HTTPS encryption.

You can also do both, so typing http://nextcloud.mypi.home redirects to https://nextcloud.mypi.home to provide encryption.

Why Nginx?

Apache HTTPD is another web server that can do reverse proxy and redirection. There are also containers like HA Proxy and Traefik that might make the work easier. Nginx has the advantage of being a lightweight system that can do the job and also serve up a few static HTML pages if you’re so inclined. It’s also widely used, so it’s easy to find configuration examples.

Removing Nginx Test

If you used the deploy-nginx-test.yml playbook previously to start an Nginx container for testing DNS and certificates, you’ll need to stop and remove it before deploying Nginx in this step. You can use Portainer to do this by clicking the Containers menu selection, or if you prefer command-line, docker-compose down will do the same thing when run from the portainer directory.

If you don’t stop and remove the old Nginx container, the new one will fail to start.

Deploying Nginx

There are two Ansible playbooks that you will use to get Nginx up and running.

The first is pre-deploy.yml and it takes care of creating directories and a couple basic files.

Second is docker-compose.yml that you can use to deploy the container, using either Portainer or docker-compose.

Because all of the remaining applications follow this same process, you will end up with a lot of files with the same names. So for Nginx deployment, move the two files into a subdirectory named nginx. When you install Gitea in the next step, create a gitea subdirectory to hold the files.

Running the pre-deploy.yml playbook will look like this:

pi@mypi:~/cloudpi/nginx $ ansible-playbook pre-deploy.yml

PLAY [Nginx Static HTML and Reverse Proxy] **************************************

TASK [Gathering Facts] **********************************************************
ok: [localhost]

TASK [Creating configuration directory] *****************************************
changed: [localhost]

TASK [Creating basic configuration file] ****************************************
changed: [localhost]

TASK [Creating a directory for static content] **********************************
changed: [localhost]

TASK [Creating a simple index.html] *********************************************
changed: [localhost]

PLAY RECAP **********************************************************************
localhost                  : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

You have some choice with docker-compose.yml. You can use the command-line docker-compose up -d or you can copy the contents of docker-compose.yml into the web editor on Portainer’s Stacks page and deploy that way.

Testing with Static HTML

Along with a new configuration file for Nginx, the pre-deploy.yml playbook also installed a simple index.html file in the Pi’s /srv/www directory. Using your client’s browser to navigate to http://mypi.home will now display a short message.

I'm not dead yet.

You should be able to reach this page using the Pi’s DNS name or IP address. It should work for HTTP and HTTPS without generating any untrusted certificate errors.

Understanding Nginx Configuration

If you look in /opt/docker/nginx/conf.d, you’ll see a single file named default.conf. This directory is where the Nginx configuration for HTTP(S) is stored. Looking at the contents of default.conf, you’ll see configuration for SSL certificates and for static files served from /srv/www and that’s all. You can edit this file and add server { } blocks to extend the configuration, but it’s generally considered better to use individual files.

Each file in the /opt/docker/nginx/conf.d will be considered part of the overall configuration.

There is additional configuration is inside the container under /etc/nginx, but only /etc/nginx/conf.d is bind mounted to the host. This directory is enough to configure redirection and reverse proxy.

Below are a couple of sample configurations. The first is a redirection for Portainer. It sends any requests on HTTP port 80 or HTTPS port 443 to port 9443 where Portainer listens for HTTPS requests. The second is a reverse proxy configuration to offload SSL connections to Nextcloud. The client web browser will connect to Nginx over HTTPS port 443 and Nginx will relay the request to Nextcloud’s unencrypted port 8910. The traffic between the client and the Pi is encrypted without configuring Nextcloud for SSL.

Redirection

server {
    server_name portainer.mypi.home;
    listen 80;
    listen 443;
    return 301 https://mypi.home:9443;
}

Reverse Proxy

server {
    server_name nextcloud.mypi.home;
    listen 443 ssl;
    location / {
        proxy_pass http://nextcloud.mypi.home:8910;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

Configuring Redirection for Portainer

So far, you’ve accessed Portainer using the URL with a port number (9000 or 9443). With Nginx running, you can configure a redirect so http://portainer.mypi.home will send the browser to the correct port. Running the post-deploy.yml Ansible playbook for Portainer will take care of the details.

The playbook output looks like this:

pi@mypi:~/cloudpi/portainer $ ansible-playbook post-deploy.yml

PLAY [Portainer post-deployment tasks] ******************************************

TASK [Gathering Facts] **********************************************************
ok: [localhost]

TASK [Checking for Nginx installation] ******************************************
ok: [localhost]

TASK [Creating redirection config] **********************************************
changed: [localhost]

RUNNING HANDLER [Reloading Nginx config] ****************************************
changed: [localhost]

PLAY RECAP **********************************************************************
localhost                  : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Configuring Redirection and Reverse Proxy per Application

The examples shown in the previous section are both very simple and will not apply well in all situations. Sometimes additional parameters are needed to handle the quirks of individual appications. For example, applications like Home Assistant and NodeRED use websockets and require extra parameters to be used with reverse proxy.

For each of the applications deployed in this document, there is an Ansible playbook called post-deploy.yml. Inside this file is a task for creating the redirection and reverse proxy configuration file that goes in /opt/docker/nginx/conf.d and a task for reloading the Nginx configuration to make it take effect.

Testing as You Go

After running post-deploy.yml in the upcoming steps, you should make a connection to the application using its HTTP URL in a web browser. URLs like http://esphome.mypi.home should result in you being sent to an encrypted (HTTPS) connection to https://esphome.mypi.home. The browser should show the connection as secure and there should be no certificate errors.

Next Steps

If you used the Portainer Stack method of deploying, you may have noticed an option for git repository on the same page as the web editor. This feature gives you the option of storing the contents of all your docker-compose.yml files in a git repository. You can pull from a public server like GitHub or GitLab, or you can keep it local. This can be done with the next application to be deployed; Gitea for self-hosted git repositories.


Tearing the S from his varsity jersey, Letterman turns HTTP into HTTPS, making web traffic encypted once again!

—The Electric Company episode we wish we had, but never did.