一生只做一次的 Nginx 反向代理配置

作为一个经常需要在 VPS 上面部署各种应用的程序员,我要说 Docker 是真的香,但配置 Nginx 是真的烦。每部署一个新的应用,都要去改一次 Nginx 的配置文件,把它指向我们新部署的应用。每当应用下线的时候,还得记得手动去把对应的配置删掉。

一生只做一次的 Nginx 反向代理配置

问题

作为一个经常需要在 VPS 上面部署各种应用的程序员,我要说 Docker 是真的香,但配置 Nginx 是真的烦。每部署一个新的应用,都要去改一次 Nginx 的配置文件,把它指向我们新部署的应用。每当应用下线的时候,还得记得手动去把对应的配置删掉。

虽然说只是改个配置文件的事情,这对于我这种又懒记性又差的人真是一件痛苦的事情。因为我根本记不住各种配置项,导致得在几个目录之间来回切换反复调试。麻烦也就算了,关键是这样一旦把 Nginx 改挂了,还会影响到其他正在运行的应用。

那么,有什么更好的办法来解决这个问题呢?

反向代理配置

nginx-proxy 这个项目帮我们解决了这个问题。

首先创建 docker-compose.yml 文件:

services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro

  acme-companion:
    image: nginxproxy/acme-companion
    container_name: nginx-proxy-acme
    environment:
      - DEFAULT_EMAIL=mail@yourdomain.tld
    volumes_from:
      - nginx-proxy
    volumes:
      - certs:/etc/nginx/certs:rw
      - acme:/etc/acme.sh
      - /var/run/docker.sock:/var/run/docker.sock:ro

volumes:
  conf:
  vhost:
  html:
  certs:
  acme:
nginx-proxy/docker-compose.yml

这里面只有 DEFAULT_EMAIL 一个地方需要修改,改为你平时常用的邮箱就行。当证书快过期没有自动续订成功时, Let's Encrypt 会给这个地址发送报警邮件。

保存好之后,启动它,从此以后我们就再也不需要维护 Nginx 的配置了。

接着我们来配置需要被代理的应用。

应用配置

记得先将域名解析配置好,然后来写应用配置。以本站的 hello.doctype-html.com 配置为例:

services:
  hello.doctype-html.com:
    image: crccheck/hello-world
    environment:
      - VIRTUAL_HOST=hello.doctype-html.com
      - LETSENCRYPT_HOST=hello.doctype-html.com
    expose:
      - "8000"

networks:
  default:
    name: nginx-proxy_default
hello.doctype-html.com/docker-compose.yml

这份配置做了三件事情。

  1. 设置 VIRTUAL_HOSTLETSENCRYPT_HOST ,分别告知 nginx-proxy 和 Let's Encrypt 本应用想要使用域名。
  2. 设置参数 expose,将此应用的端口暴露给 nginx-proxy。
  3. 设置网络信息,保证应用跟 nginx-proxy 处于同一网络。

启动它,我们就能通过配置好的域名来访问这个应用了。

深入思考

大家有没有想过为什么有人能做出 nginx-proxy 这样的项目呢?它是基于什么样的思路做出来的呢?

其实,这里面只用到了一个控制反转的思想。我们在 Nginx 的配置中给其他应用做反向代理的时候,意味着配置文件需要了解所有应用的信息。

通常情况 Nginx 配置依赖于应用信息

而 nginx-proxy 这个项目帮我们对反向代理配置做了一个抽象,定义成了一个规范,nginx-proxy 只依赖于这个规范,从而实现了与具体的应用信息的解耦。

nginx-proxy 依赖于配置规范,应用实现了配置规范

我们只要按照它的规范来实现一个新应用的配置,它就能正确识别新应用。至此,被代理的应用就被插件化了,可以随时增删,同时也不用担心某个应用的配置修改导致全局的反向代理受到影响。

今天就聊这么多,我们下次再见。