<p>Have you tried using <code>awsvpc</code> mode? <a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html" rel="nofollow noreferrer">https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html</a></p>
<p>You can follow this tutorial - <a href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/create-public-private-vpc.html" rel="nofollow noreferrer">https://docs.aws.amazon.com/AmazonECS/latest/userguide/create-public-private-vpc.html</a></p>
<p>You need a VPC, with at least two subnets, one private and one public. After that the sky is the limit ...</p>
<p>If you need internet access from the private subnet, create a NAT Gateway in the public subnet, and route traffic from the private subnet to 0.0.0.0, via the NAT Gateway - <a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html" rel="nofollow noreferrer">https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html</a></p>
<p>P.S - I never use network mode <code>host</code> with ECS, you should read more about it here - <a href="https://docs.docker.com/network/host/" rel="nofollow noreferrer">https://docs.docker.com/network/host/</a> I didn't find a strong use case for using it, except for testing purposes</p>

CC BY-SA 4.0
2020-07-14T17:31:52.383Z
`host` mode can be useful when combined with the `DAEMON` scheduling strategy on ECS. Since you know that the underlying EC2 instance will run 1 and only 1 copy of a container, you can ensure there won't be port collisions. Possible benefits: (1) Predictable port open on each EC2 instance for some sort of ancillary service (2) Because `awsvpc` mode creates an ENI for each container, its possible to run out of private IPs in a subnet in a large-scale deployment, so `host` can help alleviate that.
Woodland
CC BY-SA 4.0
2020-07-14T21:25:24.467Z
@Woodland, it's a great comment, I think you should also add it as an answer
Meir Gabay
CC BY-SA 4.0
2020-07-07T18:25:07.333Z
2020-07-07T18:49:06.337Z
2020-07-07T18:49:06.337Z
Meir Gabay
<p>First, @Meir beat me to the punch on <code>awsvpc</code> network mode, so give him a +1 and read his linked document about task networking.</p>
<hr />
<p>I'm going to expand on that and include an description of how to route to your containers from both a public-facing ALB, as well as from another container.</p>
<p>To simplify things, we're going to pretend we're running on ECS Fargate to start, and at the end I'll point how that would be different for EC2.</p>
<p>You described two ECS services: one that is public-facing behind the ALB, which we'll call <strong>frontend</strong>, and the other, which communicates to other containers internally, we will call <strong>backend</strong>.</p>
<p>Here's what <strong>frontend</strong> that might look like in Terraform:</p>
<pre><code>resource &quot;aws_ecs_task_definition&quot; &quot;frontend&quot; {
  family                   = &quot;frontend&quot;
  network_mode             = &quot;awsvpc&quot;
  requires_compatibilities = [&quot;FARGATE&quot;]
  execution_role_arn       = &quot;&quot; # generic

  container_definitions = &quot;[]&quot; # not included in example
}

resource &quot;aws_ecs_service&quot; &quot;frontend&quot; {
  name            = &quot;frontend&quot;
  cluster         = &quot;my-ecs-cluster&quot;
  task_definition = aws_ecs_task_definition.frontend.arn
  desired_count   = 2 # high availability
  launch_type     = &quot;FARGATE&quot;

  network_configuration {
    security_groups = [] # SG allowing traffic from the loadbalancer to port 8080
    subnets = [] # list of private subnets
  }

  load_balancer {
    target_group_arn = &quot;&quot; # an aws_alb_target_group
    container_name   = &quot;frontend&quot;
    container_port   = 8080
  }
}
</code></pre>
<p><strong>backend</strong> would look similar, except instead of a <code>load_balancer</code> block it would have this:</p>
<pre><code>  service_registries {
    registry_arn = aws_service_discovery_service.internal.arn
  }
</code></pre>
<p>And these new resources:</p>
<pre><code>resource &quot;aws_service_discovery_private_dns_namespace&quot; &quot;internal&quot; {
  name = &quot;internal.dev&quot;
  vpc  = &quot;&quot; # a vpc id
}

resource &quot;aws_service_discovery_service&quot; &quot;backend&quot; {
  name = &quot;backend&quot;

  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.internal.id
    dns_records {
      ttl  = 10
      type = &quot;A&quot;
    }
  }
}
</code></pre>
<p>Service Discovery creates and manages DNS records for the private IPs (ENIs) of your <strong>backend</strong> tasks automatically. That means <code>backend.internal.dev</code> now resolves to one of those IPs in your VPC CIDRs, something like <code>10.10.0.60</code>.</p>
<p>Now when <strong>frontend</strong> wants to connect to <strong>backend</strong>, it can do so via <code>backend.internal.dev</code>. No internal ALB required! Your entire VPC can resolve that domain.</p>
<hr />
<p><em>&quot;Okay, but how does this work on EC2?&quot;</em> you might ask. Well, that's the beauty of <code>awsvpc</code> network mode... it works the same way! These task ENIs are completely different network devices than your EC2 instance's ENI. You will need to modify the Terraform slightly, and perhaps review your security groups, but ultimately nothing has changed: the ALB still connects to the <strong>frontend</strong> task ENI, and the <strong>backend</strong> task ENI is still registered in service discovery. You can run multiples of the same container on a single EC2 instance without port collision because they are using different network interfaces.</p>
<hr />
<p>References:</p>
<p><a href="https://aws.amazon.com/blogs/aws/amazon-ecs-service-discovery/" rel="nofollow noreferrer">https://aws.amazon.com/blogs/aws/amazon-ecs-service-discovery/</a>
<a href="https://aws.amazon.com/about-aws/whats-new/2019/06/Amazon-ECS-Improves-ENI-Density-Limits-for-awsvpc-Networking-Mode/" rel="nofollow noreferrer">https://aws.amazon.com/about-aws/whats-new/2019/06/Amazon-ECS-Improves-ENI-Density-Limits-for-awsvpc-Networking-Mode/</a></p>

CC BY-SA 4.0
2020-07-14T23:08:50.220Z
2020-07-15T00:04:29.007Z
2020-07-15T00:04:29.007Z
Woodland
<p>Regardless of instance count, you can publish only the port of publicly available app by adding security rule which will allow external traffic into that port's bound host's port, and for the second one just bridge to the first app</p>

CC BY-SA 4.0
2020-07-09T19:18:30.010Z
2020-07-09T19:18:30.010Z
Hakob
<p>Suppose I have two apps launched via the AWS ECS cluster (using Docker containers).</p>
<p>I want to expose one app to the world via a public IP (and I do it via the AWS load balancer) but the other one I want to be able to access only internally, so that it would not have any public IPs and would only be accessible internally.</p>
<p>Is this possible to do that at all? I suppose it should be easier via docker containers because I could possibly make them communicate to each other by exposing a localhost via</p>
<pre><code>--network=&quot;host&quot; in docker run
</code></pre>
<p>But that would work if I run the two apps on the same EC2 instance.</p>
<p>What if I run them on separate instances but they are using the same load balancer or — separate instances but in the same AWS zone?</p>
<p>What setting would I use in ECS to expose this app only via the localhost?</p>

<docker><amazon-web-services><amazon-ecs>
Accessing a AWS docker instance via localhost only?
Aerodynamika
# Accessing a AWS docker instance via localhost only?

(Asked by: username_0 on 2020-07-07)

Suppose I have two apps launched via the AWS ECS cluster (using Docker containers).
I want to expose one app to the world via a public IP (and I do it via the AWS load balancer) but the other one I want to be able to access only internally, so that it would not have any public IPs and would only be accessible internally.
Is this possible to do that at all? I suppose it should be easier via docker containers because I could possibly make them communicate to each other by exposing a localhost via
--network="host" in docker run

But that would work if I run the two apps on the same EC2 instance.
What if I run them on separate instances but they are using the same load balancer or — separate instances but in the same AWS zone?
What setting would I use in ECS to expose this app only via the localhost?

**Tags:** docker, amazon-web-services, amazon-ecs


---

## 3 answers

### Answer by username_1 on 2020-07-07. Score: 3

Have you tried using `awsvpc` mode? <https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html>

You can follow this tutorial - <https://docs.aws.amazon.com/AmazonECS/latest/userguide/create-public-private-vpc.html>

You need a VPC, with at least two subnets, one private and one public. After that the sky is the limit ...

If you need internet access from the private subnet, create a NAT Gateway in the public subnet, and route traffic from the private subnet to 0.0.0.0, via the NAT Gateway - <https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html>

P.S - I never use network mode `host` with ECS, you should read more about it here - <https://docs.docker.com/network/host/> I didn't find a strong use case for using it, except for testing purposes

> **Comments:**
> **username_2**: `host` mode can be useful when combined with the `DAEMON` scheduling strategy on ECS. Since you know that the underlying EC2 instance will run 1 and only 1 copy of a container, you can ensure there won't be port collisions. Possible benefits: (1) Predictable port open on each EC2 instance for some sort of ancillary service (2) Because `awsvpc` mode creates an ENI for each container, its possible to run out of private IPs in a subnet in a large-scale deployment, so `host` can help alleviate that.  
> **username_1**: @username_2, it's a great comment, I think you should also add it as an answer  

---

### Answer by username_2 on 2020-07-14. Score: 2

First, @Meir beat me to the punch on awsvpc network mode, so give him a +1 and read his linked document about task networking.

I'm going to expand on that and include an description of how to route to your containers from both a public-facing ALB, as well as from another container.
To simplify things, we're going to pretend we're running on ECS Fargate to start, and at the end I'll point how that would be different for EC2.
You described two ECS services: one that is public-facing behind the ALB, which we'll call frontend, and the other, which communicates to other containers internally, we will call backend.
Here's what frontend that might look like in Terraform:
resource "aws_ecs_task_definition" "frontend" {
  family                   = "frontend"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  execution_role_arn       = "" # generic

  container_definitions = "[]" # not included in example
}

resource "aws_ecs_service" "frontend" {
  name            = "frontend"
  cluster         = "my-ecs-cluster"
  task_definition = aws_ecs_task_definition.frontend.arn
  desired_count   = 2 # high availability
  launch_type     = "FARGATE"

  network_configuration {
    security_groups = [] # SG allowing traffic from the loadbalancer to port 8080
    subnets = [] # list of private subnets
  }

  load_balancer {
    target_group_arn = "" # an aws_alb_target_group
    container_name   = "frontend"
    container_port   = 8080
  }
}

backend would look similar, except instead of a load_balancer block it would have this:
  service_registries {
    registry_arn = aws_service_discovery_service.internal.arn
  }

And these new resources:
resource "aws_service_discovery_private_dns_namespace" "internal" {
  name = "internal.dev"
  vpc  = "" # a vpc id
}

resource "aws_service_discovery_service" "backend" {
  name = "backend"

  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.internal.id
    dns_records {
      ttl  = 10
      type = "A"
    }
  }
}

Service Discovery creates and manages DNS records for the private IPs (ENIs) of your backend tasks automatically. That means backend.internal.dev now resolves to one of those IPs in your VPC CIDRs, something like 10.10.0.60.
Now when frontend wants to connect to backend, it can do so via backend.internal.dev. No internal ALB required! Your entire VPC can resolve that domain.

"Okay, but how does this work on EC2?" you might ask. Well, that's the beauty of awsvpc network mode... it works the same way! These task ENIs are completely different network devices than your EC2 instance's ENI. You will need to modify the Terraform slightly, and perhaps review your security groups, but ultimately nothing has changed: the ALB still connects to the frontend task ENI, and the backend task ENI is still registered in service discovery. You can run multiples of the same container on a single EC2 instance without port collision because they are using different network interfaces.

References:
https://aws.amazon.com/blogs/aws/amazon-ecs-service-discovery/
https://aws.amazon.com/about-aws/whats-new/2019/06/Amazon-ECS-Improves-ENI-Density-Limits-for-awsvpc-Networking-Mode/


---

### Answer by username_3 on 2020-07-09. Score: 0

Regardless of instance count, you can publish only the port of publicly available app by adding security rule which will allow external traffic into that port's bound host's port, and for the second one just bridge to the first app


---

