Nginx reverse proxy + Docker: how this server is set up

The goal of this setup is to have subdomains on the server, each of which is managed by a docker container. Oh, and each of these containers needs to have HTTPS.

The overview is pretty simple: the server is essentially just hardware for Docker to run on. Docker has images that both reverse-proxy (allowing subdomains) and generate SSLs automatically (allowing HTTPS). Subsequent containers simply need to declare their domain of operation (which can actually be any domain that you control the DNS of) and any Docker setup requirements (perhaps a database).

So, let's get started.

Getting Docker

This part is pretty easy so I won't spend much time explaining anything: just install docker and docker-compose with apt install docker.io docker-compose. Make sure to apt update your server if needed.

Getting Nginx, proxying, and SSL

So this is the secret sauce here. Jason Wilder and Nicolas Duchon have incredible repositories to make this process simple and we're lucky enough to have it for free and open source. Here is the git repository that documents how to do everything, which I also have below:

1. Get nginx-proxy up

docker run --detach \ 
--name nginx-proxy \ 
--publish 80:80 \ 
--publish 443:443 \ 
--volume /etc/nginx/certs \ 
--volume /etc/nginx/vhost.d \ 
--volume /usr/share/nginx/html \ 
--volume /var/run/docker.sock:/tmp/docker.sock:ro \ 
jwilder/nginx-proxy

2. Get letsencrypt-nginx-proxy-companion up

docker run --detach \
--name nginx-proxy-letsencrypt \
--volumes-from nginx-proxy \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
--volume /etc/acme.sh \
--env "[email protected]" \
jrcs/letsencrypt-nginx-proxy-companion

3. Make some containers

docker run -d \
--name proxied-app \
--network=webproxy \
-e "VIRTUAL_HOST=sub.yourdomain.tld" \
-e "LETSENCRYPT_HOST=sub.yourdomain.tld" \
container/container

Some notes

Here's some things you might want to consider as you make your containers:

Connecting databases (or any containers)
After creating the image, ensure that any image that uses the database is on the same network (I set it as --network=webproxy)

Persistent storage
This is useful for not losing data (I recommend doing it for all containers, especially databases). Just add -v /path/to/local:/path/to/container to your docker run script, where /path/to/local is the location on your machine, and /path/to/container is the path within the Docker container you want to have persist on the machine when the container is gone.

Change allowed upload size (useful for clouds)
Since there are potentially many subdomains or even many domains on this server, setting max file upload size has to happen on the server-wide config, not on the specific subdomain. Bash into the container:
docker exec -it nginx-proxy bash
and then edit the nginx.conf file:
nano /etc/nginx/nginx.conf
You'll need to add client_max_body_size 8M; near the end of the http{..} block to make the upload size 8MB (obviously change the number as you desire). Mine looked like this when I was done:

http {
    
    # other code...

    # upload size 8MB
    client_max_body_size 8M;

    include /etc/nginx/conf.d/*.conf;
}

When you've done that, go ahead and service nginx restart to reboot nginx with the new config. You'll probably need to restart the container in Docker too: docker stop nginx-proxy && docker start nginx-proxy