Docker implements automatic reverse proxy through nginx-proxy

foreword

When using docker , if there are multiple docker containers serving as websites, nginx is a bit troublesome to configure whether it is installed separately or as a docker container. The use of nginx-proxy can complete the automatic reverse proxy of the docker container through simple configuration .

text

We use docker-compose to configure docker services.

In order to easily distinguish the development and production environments, we create three configuration files:

  • docker-compose.yml
  • docker-compose.dev.yml
  • docker-compose.prod.yml

docker-compose.yml is the basic configuration of all service software:

version: '3'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy:0.8.0
    container_name: nginx-proxy
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - /docker/volumes/nginx/conf:/etc/nginx/conf.d  #其他配置文件目录挂载
      - /docker/volumes/nginx/vhost:/etc/nginx/vhost.d  #虚拟主机配置文件目录挂载
      - /docker/volumes/nginx/html:/usr/share/nginx/html  #静态资源根目录挂载
      - /docker/volumes/nginx/dhparam:/etc/nginx/dhparam
      - /docker/volumes/nginx/certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      #- /docker/volumes/nginx/log:/var/log/nginx #日志文件挂载
  halo:
    image: ruibaby/halo
    container_name: halo
    restart: always
    volumes:
      - ~/.halo:/root/.halo #项目资源挂载
      - /etc/localtime:/etc/localtime:ro
  gogs:
    image: gogs/gogs:0.12
    container_name: gogs
    restart: always
    volumes:
      - /docker/volumes/gogs/data:/data
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
  jenkins:
    image: jenkins/jenkins:2.263.1-lts-centos7
    container_name: jenkins
    restart: always
    volumes:
      - /docker/volumes/jenkins/jenkins_home:/var/jenkins_home
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

docker-compose.dev.yml is used to configure the development and testing of service software (not used in this example, can be ignored):

version: '3'
services:
  halo:
    ports:
      - 8090:8090
  gogs:
    ports:
      - 3000:3000
  jenkins:
    ports:
      - 8888:8080
      - 50000:50000

docker-compose.prod.yml is for official environment, which contains nginx-proxy related configuration

version: '3'
services:
  halo:
    environment:
      - VIRTUAL_HOST=xxx.com,www.xxx.com
      - VIRTUAL_PORT=8090
  gogs:
    environment:
      - VIRTUAL_HOST=git.xxx.com
      - VIRTUAL_PORT=3000
  jenkins:
    environment:
      - VIRTUAL_HOST=jks.xxx.com
      - VIRTUAL_PORT=8080

The xxx.com inside is replaced by the official domain name. The most important thing here are the two environment variables VIRTUAL_HOST and VIRTUAL_PORT . VIRTUAL_HOST configures the domain name you want to reverse proxy, and VIRTUAL_PORT is the internal port of the website service container.

The correct way to write environment variables

There is one thing to note here. There are two correct ways to write environment variables as follows:

environment:
      - VIRTUAL_HOST=xxx.com
      - VIRTUAL_PORT=80
environment:
      VIRTUAL_HOST: xxx.com
      VIRTUAL_PORT: 80

Other ways of writing nginx-proxy cannot be recognized.

Principle of automatic reverse proxy

The nginx-proxy container exposes port 80 to the outside, and listens to port 80, allowing traffic on port 80 to flow in.
By setting the mount point: /var/run/docker.sock:/tmp/docker.sock , allow the nginx-proxy container to access the Docker socket of the host machine, which means that when a new container is added, or when the new container is closed Notify to nginx-proxy container.

In this way, every time a container is added, nginx-proxy will receive the event through the socket, automatically create the corresponding configuration file, and then restart nginx to take effect. nginx-proxy will look for a container with the VIRTUAL_HOST environment variable, and then follow the configuration.

Start the container

We want to see the effect of automatic reverse proxy, run the following command directly:

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

The output is as follows:

[root@iZuf6gt0uel6sln10ai38rZ docker]# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Creating network "docker_default" with the default driver
Creating jenkins      ... done
Creating gogs         ... done
Creating nginx-proxy  ... done
Creating halo         ... done

Check the default.conf file under the host's /docker/volumes/nginx/conf folder . At the end of the file, you can see that nginx-proxy automatically generates the following content:

# git.xxx.com
upstream git.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# gogs
			server 192.168.128.5:3000;
}
server {
    
    
	server_name git.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	location / {
    
    
		proxy_pass http://git.xxx.com;
	}
}
# xxx.com
upstream xxx.com {
    
    
				## Can be connected with "docker_default" network
			# halo
			server 192.168.128.8:8090;
}
server {
    
    
	server_name xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	location / {
    
    
		proxy_pass http://xxx.com;
	}
}
# jks.xxx.com
upstream jks.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# jenkins
			server 192.168.128.4:8080;
}
server {
    
    
	server_name jks.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	location / {
    
    
		proxy_pass http://jks.xxx.com;
	}
}
# www.xxx.com
upstream www.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# halo
			server 192.168.128.8:8090;
}
server {
    
    
	server_name www.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	location / {
    
    
		proxy_pass http://www.xxx.com;
	}
}

If you have resolved the domain names of the above services, you can already access the domain names xxx.com , www.xxx.com , git.xxx.com , and jks.xxx.com normally.

HTTPS automatic configuration

nginx-proxy has a corresponding project letsencrypt-nginx-proxy-companion , which can automatically create and renew Let's Encrypt certificates.

However, Alibaba Cloud’s free DV certificate is used here:
insert image description here
click “Buy Certificate” and select a free certificate: Although
insert image description here
nginx-proxy is based on nginx , it can only automatically recognize the certificate of the combination of .crt and .key, so we download the Apache certificate:
insert image description here
Unzip the downloaded 4927566_xxx.com_apache.zip file, rename the 4927566_xxx.com_public.crt and 4927566_xxx.com.key files inside to xxx.com.crt and xxx.com.key, and put them into /docker/volumes on the host /nginx/certs folder ( mount point for the certificate folder /etc/nginx/certs ).

If your xxx.com.crt and xxx.com.key certificates are wildcard certificates applicable to all third-level domain names, just put in this pair of certificates. A free single domain name certificate is used here, and all third-level domain name certificates must be placed under the above certificate folder.

Restart the nginx-proxy container and run the following command:

docker-compose restart

Check the default.conf file under the host's /docker/volumes/nginx/conf folder . At the end of the file, you can see that nginx-proxy automatically generates the following content:

# git.xxx.com
upstream git.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# gogs
			server 192.168.128.3:3000;
}
server {
    
    
	server_name git.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	# Do not HTTPS redirect Let'sEncrypt ACME challenge
	location /.well-known/acme-challenge/ {
    
    
		auth_basic off;
		allow all;
		root /usr/share/nginx/html;
		try_files $uri =404;
		break;
	}
	location / {
    
    
		return 301 https://$host$request_uri;
	}
}
server {
    
    
	server_name git.xxx.com;
	listen 443 ssl http2 ;
	access_log /var/log/nginx/access.log vhost;
	ssl_session_timeout 5m;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;
	ssl_certificate /etc/nginx/certs/git.xxx.com.crt;
	ssl_certificate_key /etc/nginx/certs/git.xxx.com.key;
	add_header Strict-Transport-Security "max-age=31536000" always;
	location / {
    
    
		proxy_pass http://git.xxx.com;
	}
}
# xxx.com
upstream xxx.com {
    
    
				## Can be connected with "docker_default" network
			# halo
			server 192.168.128.8:8090;
}
server {
    
    
	server_name xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	# Do not HTTPS redirect Let'sEncrypt ACME challenge
	location /.well-known/acme-challenge/ {
    
    
		auth_basic off;
		allow all;
		root /usr/share/nginx/html;
		try_files $uri =404;
		break;
	}
	location / {
    
    
		return 301 https://$host$request_uri;
	}
}
server {
    
    
	server_name xxx.com;
	listen 443 ssl http2 ;
	access_log /var/log/nginx/access.log vhost;
	ssl_session_timeout 5m;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;
	ssl_certificate /etc/nginx/certs/xxx.com.crt;
	ssl_certificate_key /etc/nginx/certs/xxx.com.key;
	add_header Strict-Transport-Security "max-age=31536000" always;
	location / {
    
    
		proxy_pass http://xxx.com;
	}
}
# jks.xxx.com
upstream jks.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# jenkins
			server 192.168.128.4:8080;
}
server {
    
    
	server_name jks.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	# Do not HTTPS redirect Let'sEncrypt ACME challenge
	location /.well-known/acme-challenge/ {
    
    
		auth_basic off;
		allow all;
		root /usr/share/nginx/html;
		try_files $uri =404;
		break;
	}
	location / {
    
    
		return 301 https://$host$request_uri;
	}
}
server {
    
    
	server_name jks.xxx.com;
	listen 443 ssl http2 ;
	access_log /var/log/nginx/access.log vhost;
	ssl_session_timeout 5m;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;
	ssl_certificate /etc/nginx/certs/jks.xxx.com.crt;
	ssl_certificate_key /etc/nginx/certs/jks.xxx.com.key;
	add_header Strict-Transport-Security "max-age=31536000" always;
	location / {
    
    
		proxy_pass http://jks.xxx.com;
	}
}
# www.xxx.com
upstream www.xxx.com {
    
    
				## Can be connected with "docker_default" network
			# halo
			server 192.168.128.8:8090;
}
server {
    
    
	server_name www.xxx.com;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	# Do not HTTPS redirect Let'sEncrypt ACME challenge
	location /.well-known/acme-challenge/ {
    
    
		auth_basic off;
		allow all;
		root /usr/share/nginx/html;
		try_files $uri =404;
		break;
	}
	location / {
    
    
		return 301 https://$host$request_uri;
	}
}
server {
    
    
	server_name www.xxx.com;
	listen 443 ssl http2 ;
	access_log /var/log/nginx/access.log vhost;
	ssl_session_timeout 5m;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;
	ssl_certificate /etc/nginx/certs/xxx.com.crt;
	ssl_certificate_key /etc/nginx/certs/xxx.com.key;
	add_header Strict-Transport-Security "max-age=31536000" always;
	location / {
    
    
		proxy_pass http://www.xxx.com;
	}
}

You can see that nginx-proxy has automatically generated SSL- related configurations.

If the domain name resolution is normal, you can now access the website normally through https.

Points to note when using HTTPS

We can see from the SSL configuration information generated above that port 80 of http jumps to port 443 of https by default.

If we want both http and https to be accessible normally, we can add environment variables:

      - HTTPS_METHOD=noredirect

If one of our domain names does not want to be accessed through https, we can add environment variables:

      - HTTPS_METHOD=nohttps

After adding the above environment variables, you need to stop and delete the container, and then start the container to make the environment variables take effect:

docker-compose down
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

reference link

https://hub.docker.com/r/jwilder/nginx-proxy

Guess you like

Origin blog.csdn.net/hanshiying007/article/details/111284400