Gateway / reverse proxy / load balancer: Instead of exposing a bunch of different backend services separately, have nginx route requests to the appropriate backend.
If you have multiple instances of the same service, you can automatically balance the load using simple round robin or least connection based strategies.
In terms of authentication, basic user/pass based authentication is possible. nginx plus, which is not free, supports more advanced authentication methods, but it's still possible to use nginx too, with a bit more extra work.
The configuration file is /etc/nginx/conf.d/default.conf, which uses a domain specific language looking like:
upstream backend_name {
least_conn; # load balancing strategy
server 10.10.10.1:80 weight = 5; # weight used in load balancing
server 10.10.10.2:8080;
...
server 10.10.10.10:80 backup;
}
server {
# Standard HTTP Protocol
listen 80;
# Standard HTTPS Protocol
listen 443 ssl;
# Listen on 80 using IPv6
listen [::]:80;
# Listen only on using IPv6
listen [::]:80 ipv6only=on;
# configuration of HTTP virtual server 1
location /one {
# configuration for processing URIs starting with '/one'
}
location /two {
# configuration for processing URIs starting with '/two'
}
}
# reverse proxy and load balancing
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://backend_name;
}
}
# and then to redirect
server {
listen 80;
return 301 http://yourdomain.com$request_uri; redirect
}
# reverse proxy. pass the header
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://10.10.10.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Proxy keepalive for websocket
# Upstreams
upstream backend {
server 127.0.0.1:3000;
keepalive 5;
}
# HTTP Server
server {
server_name your_hostname.com;
error_log /var/log/nginx/rocketchat.access.log;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
}I needed to generate nginx.conf dynamically, depending on the addresses/hostnames of the services that are spun up. Note that in docker-compose you can't specify the hostname based on an environment variable. Service names are string literals. You can use --project-name when docker compose up, to pass a project name which will be prefixed to the container, volume, and network names to avoid conflicts.
But whatever those names are, you can define as variables in an nginx.conf.template file, and then use envsubst to replace the names.
envsubst < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'In docker-compose terms:
image: nginx
volumes:
- ./my-site.tmpl:/etc/nginx/conf.d/my-site.conf.template
ports:
- "8080:80"
environment:
- HOST=my-site.com
- PORT=80
- SERVER_NAME="my-site"
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"Just be careful with the built-in NGINX variables $host and $connection etc. Just use less generic names.