0

I am setting up my Ruby on Rails application on AWS ECS and would like to redirect my website, example.com, to www.example.com. I am running into an issue with redirecting my Nginx upstream server to my Rails app. Everything seems to work fine locally. My Docker container crashes with the following error message:

[emerg] 8#8: host not found in upstream "web:3000" in /etc/nginx/conf.d/default.conf:3
nginx: [emerg] host not found in upstream "web:3000" in /etc/nginx/conf.d/default.conf:3

Here's my docker-compose.yml:

version: '3'

services:
  web:
    build:
      args:
        DEPLOY_ENV_ARG: ${DEPLOY_ENV:-development}
        SERVER_ENV_ARG: ${SERVER_ENV:-development}
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"

  nginx:
    build:
      dockerfile: Dockerfile.nginx
    links:
      - web
    ports:
      - "80:80"

Dockerfile.nginx

FROM nginx:1.23-alpine

COPY ./nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

nginx.conf

upstream rails_app {
  server web:3000;
}

server {
  server_name example.com;

  # Redirect all http://example.com requests to http://www.example.com
  return 301 $scheme://www.$server_name$request_uri;
}

server {
  listen 80;
  listen [::]:80;
  # server_name www.example.com;
  server_name xxxxx-xxxxx-xxxx-xxxx.us-west-2.elb.amazonaws.com; # My ALB address hostname

  # Specify the public application root
  root   /example/public;

  # Specify where Nginx should write its logs
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  # Deny requests for files that should never be accessed such as .rb or .log files
  location ~ /\. {
    deny all;
  }

  location ~* ^.+\.(rb|log)$ {
    deny all;
  }

  # Serve static (compiled) assets directly
  location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/   {
    try_files $uri @rails;
    access_log off;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Last-Modified "";
    add_header ETag "";
    break;
  }

  # Send non-static file requests to the app server
  location / {
    try_files $uri @rails;
  }

  # Reverse proxy redirecting the request to the rails app, port 3000.
  location @rails {
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://rails_app;
    proxy_read_timeout 900;
  }
}

If it's helpful, here's the output of docker ps:

CONTAINER ID   IMAGE                                                                             COMMAND
  CREATED          STATUS                  PORTS                                       NAMES
4634eafd0ac1   xxxxxxxxxx.xxx.xxx.us-west-2.amazonaws.com/example_web_production:latest      "./docker/web-entryp…"   3 seconds ago    Up 2 seconds            0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   ecs-example_web_production-10-web-aad0d39b88a584e02800
3385ac3e9bcd   amazon/amazon-ecs-agent:latest                                                    "/agent"
  37 hours ago     Up 37 hours (healthy)                                               ecs-agent

How can I get the Nginx config to recognize the web container running on the same instance?

Alexander
  • 3,959
  • 2
  • 31
  • 58
  • try to add `depends_on`. may be the `web` container still doesn't exist when `nginx` starts – Yuri G. Jul 04 '22 at 04:43
  • Proxy_pass does not see rails_app. – MikiBelavista Jul 04 '22 at 04:48
  • @MikiBelavista Can you elaborate please? All the examples I found show a setup like this, using an upstream in the proxy_pass. – Alexander Jul 04 '22 at 08:27
  • @Alexander try to inspect both containers. You can also put them on the same bridge network. – MikiBelavista Jul 04 '22 at 15:21
  • @YuriG @MikiBelavista thank you, but those solutions unfortunately didn't work. It seems that the container name in AWS is dynamically set, so `web` doesn't seem to exist. Is there a way to dynamically retrieve the docker container name? – Alexander Jul 05 '22 at 03:26

1 Answers1

0

I fixed it! Nginx could not find the web container because the links between the nginx and web containers were not set in the AWS ECS task definition. This is what my task definition looked like before:

{
  ...
  "containerDefinitions": [
    {
      "name": "nginx",
      "image": "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/nginx:latest",
      "cpu": 0,
      "links": [],
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 0,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      ...
    },
    {
      "name": "web",
      "image": "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/web:latest",
      "cpu": 0,
      "links": [],
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      ...
    }
  ]

  ...
}

Now it looks like the following (note the links):

{
  ...
  "containerDefinitions": [
    {
      "name": "nginx",
      "image": "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/nginx:latest",
      "cpu": 0,
      "links": [
        "web"
      ],
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 0,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      ...
    },
    {
      "name": "web",
      "image": "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/web:latest",
      "cpu": 0,
      "links": [],
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      ...
    }
  ]

  ...
}

I had to use the old ECS console in order to add the web container as link; the new console doesn't have that option yet. See this SO answer for a screenshot.

Alexander
  • 3,959
  • 2
  • 31
  • 58