在单独的Docker容器中反向代理Nginx和Rails

时间:2018-11-28 22:37:31

标签: ruby-on-rails docker nginx

大家好,我正在尝试使用nginx作为反向代理使我的rails应用工作,rails应用和nginx位于单独的docker容器中,并通过docker-compose服务工作。我直到现在都没有成功。

设置环境production.rb => config.force_ssl = true

我的docker-compose文件是这样的:

version: '3'

services: 
  nginx:
    image: reverse_nginx:latest
    ports:
      - '80:80'
    depends_on:
      - web

  web:
    image: production_my_app:latest
    command: rails s -p 3000 -b '0.0.0.0' -e production
    ports:
      - '3000:3000'
    depends_on:
      - postgres
      - redis
    env_file:
      - ...
    restart: always

对于构建reverse_nginx:latest我将Dockerfile-nginx用于此:

# Base image: debian strech
FROM nginx:stable

RUN apt-get update -qq \
  && apt-get install -y ca-certificates

COPY ssl/server.crt /etc/ssl/certs/server.crt
COPY ssl/server.key /etc/ssl/private/server.key

RUN cd /etc/ssl/private \
  && chmod 600 server.* \
  && cd /etc/ssl/certs \
  && chmod 600 server.* \
  && update-ca-certificates --fresh

# establish where Nginx should look for files
ENV RAILS_ROOT /var/www/my_app/public

# Set working directory inside the image
WORKDIR $RAILS_ROOT

# create log directory
RUN mkdir log

# copy over static assets
COPY public .

# copy custom general nginx conf
COPY config/nginx.conf /etc/nginx/nginx.conf

# copy custom conf for my_app to sites-available folder
COPY config/my.app.conf /etc/nginx/sites-available/my.app.conf

# create sites-enabled folder and soft link custom conf for my_app
RUN mkdir -p /etc/nginx/sites-enabled/ \
  && cd /etc/nginx/sites-enabled/ \
  && ln -s /etc/nginx/sites-available/my.app.conf . \
  && ls -la \
  && nginx -c /etc/nginx/nginx.conf -t

EXPOSE 80

CMD [ "nginx", "-g", "daemon off;" ]

/etc/nginx/nginx.conf文件:

user nginx;
worker_processes auto;
worker_rlimit_nofile 1024;

events {
    multi_accept on;
    worker_connections 1024;
}

http {
    # load configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*.conf;

    # MIME
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 2048;
    client_max_body_size 16M;

    # SSL
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # modern configuration
    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
    ssl_prefer_server_ciphers on;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
    # resolver_timeout 2s;
}

/etc/nginx/sites-available/my_app.conf文件:

# HTTPS
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  server_name my.app;
  root /var/www/myapp/public;

  ssl_certificate /etc/ssl/certs/server.crt;
  ssl_certificate_key /etc/ssl/private/server.key;

  # index.html fallback
  location / {
    try_files $uri $uri/ /index.html;
  }

  # reverse proxy
  location /var/www/myapp/public {

    # proxy_pass needs to be name of service on docker compose to connect with container?
    proxy_pass http://web:3000;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

# HTTP redirect to HTTPS
server {
  listen 80;
  listen [::]:80;

  server_name .my.app;

  return 301 https://my.app$request_uri;
}

场景:

$ docker-compose up nginx_1 =>消息(如预期):

nginx_1 | "ssl_stapling" ignored, issuer certificate not found for certificate "/etc/ssl/certs/server.crt"

场景1:在浏览器中访问0.0.0.0,URL更改为https://my.app浏览器时说:ERR_SSL_PROTOCOL_ERROR

场景2:在浏览器中访问0.0.0.0:80,将网址更改为https://my.app浏览器时说:ERR_SSL_PROTOCOL_ERROR

场景3:在浏览器中访问0.0.0.0:3000,URL更改为https://0.0.0.0:3000 rails错误日志HTTPS解析错误格式错误的无效HTTP格式解析失败,浏览器说:ERR_SSL_PROTOCOL_ERROR

场景4:访问https://0.0.0.0:80,URL保持不变,nginx_1日志抛出字符:192.168.0.1 - - [28/Nov/2018:21:39:22 +0000] "\x16\x03\x01\x00\xB5\x01\x00\x00\xB1\x03\x03\xD3@kn" 400 166 "-" "-"

我认为问题出在my_app.conf中的proxy_pass指令中,但老实说,我不知道自己现在在做什么。您能帮我了解发生了什么吗?我从未使用过nginx

1 个答案:

答案 0 :(得分:1)

您遇到一些问题:

  • 要找到SSL证书,需要对其进行修复,以消除SSL错误

  • 位置应指向您正在访问的网址(这是一个正则表达式)

  • nginx不了解docker

  • 服务器名称配置不正确

代理通行证

要以相反的顺序解决这些问题,请不要将传递代理到http://web,而传递给您在以下位置启动容器的地址:http://0.0.0.0:3000

位置

接下来,您似乎想要将所有将反向代理击中的Web通信都代理到rails。如果是这种情况,则将其设置为唯一的位置障碍,并将其设置为location / { ... }

示例:

# reverse proxy
location / {
  # pass everything to rails
  proxy_pass http://0.0.0.0:3000;

  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}

SSL

您可能需要组合证书,但我首先要检查以确保您的证书实际上位于配置中列出的路径上

服务器名称

Nginx将让多个主机使用相同的IP地址并进行适当的路由。这基于server_name指令。看来您希望所有通向0.0.0.0(或最终主机)的流量都被代理到rails。因此,最好的办法就是添加catchall。在:80:443服务器块中,将server_name my.app;更改为server_name _ my.app;。此处,_充当通配符。如果不这样做,您将需要编辑/etc/hosts文件并将my.app指向localhost,然后通过转到https://my.app而不是0.0.0.0来访问它。 / p>