Skip to content

Instantly share code, notes, and snippets.

@makomweb
Last active July 22, 2026 19:04
Show Gist options
  • Select an option

  • Save makomweb/5e5aacf79c05d02bf3859b7abeb8eb2b to your computer and use it in GitHub Desktop.

Select an option

Save makomweb/5e5aacf79c05d02bf3859b7abeb8eb2b to your computer and use it in GitHub Desktop.
NGINX auf ECS Fargate (AWS)

NGINX on ECS Fargate (AWS)

Architecture Diagram

graph TB
    Internet["🌐 Internet<br/>User/Client"]
    
    subgraph Region["<b>Region: eu-central-1</b>"]
        subgraph VPC_BOX["<b>VPC: 10.0.0.0/16</b><br/>(spans multiple AZs)"]
            IGW["<b>Internet Gateway</b><br/>igw-xxx"]
            RouteTable["<b>Route Table</b><br/>0.0.0.0/0 β†’ Subnet"]
            
            subgraph AZ_1a["<b>AZ: eu-central-1a</b>"]
                Subnet["<b>Public Subnet</b><br/>10.0.1.0/24"]
                
                SG["<b>Security Group</b><br/>nginx-sg"]
                SG_Rule["<b>Inbound</b><br/>TCP/80 from 0.0.0.0/0"]
                
                ENI["<b>Elastic Network Interface</b><br/>Public IP 3.125.45.67"]
                
                Service["<b>ECS Service</b><br/>my-service"]
                TaskDef["<b>Task Definition</b><br/>my-server-family:1"]
                Fargate["<b>AWS Fargate</b><br/>Serverless Compute"]
                Container["<b>nginx:latest</b><br/>Port 80"]
            end
            
            AZ_1b["<b>AZ: eu-central-1b</b><br/>(additional subnets possible)"]
            AZ_1c["<b>AZ: eu-central-1c</b><br/>(additional subnets possible)"]
        end
    end
    
    Internet -->|HTTP/80| IGW
    IGW -->|Routes via| RouteTable
    RouteTable -->|Directs to| Subnet
    
    Subnet -->|Contains| SG
    SG_Rule -.->|Rule| SG
    SG -->|Allows| ENI
    
    Service -->|Orchestrates| TaskDef
    TaskDef -->|Deploys to| Fargate
    Fargate -->|Runs| Container
    Container -->|Binds to| ENI
    
    ENI -.->|Response| Internet
    
    style Internet fill:#FFF4E6,stroke:#FF9800,stroke-width:3px
    style Region fill:#FAFAFA,stroke:#424242,stroke-width:3px
    style VPC_BOX fill:#E3F2FD,stroke:#1976D2,stroke-width:3px
    style AZ_1a fill:#F5F5F5,stroke:#616161,stroke-width:2px,stroke-dasharray: 5 5
    style AZ_1b fill:#F5F5F5,stroke:#616161,stroke-width:2px,stroke-dasharray: 5 5
    style AZ_1c fill:#F5F5F5,stroke:#616161,stroke-width:2px,stroke-dasharray: 5 5
    style IGW fill:#C8E6C9,stroke:#388E3C,stroke-width:2px
    style RouteTable fill:#E8F5E9,stroke:#558B2F,stroke-width:2px
    style Subnet fill:#E1F5FE,stroke:#0097A7,stroke-width:2px
    style SG fill:#FCE4EC,stroke:#C2185B,stroke-width:2px
    style SG_Rule fill:#F8BBD0,stroke:#C2185B,stroke-width:1px
    style ENI fill:#FFF9C4,stroke:#F57F17,stroke-width:2px
    style Service fill:#F1F8E9,stroke:#689F38,stroke-width:2px
    style TaskDef fill:#F1F8E9,stroke:#689F38,stroke-width:2px
    style Fargate fill:#E0F2F1,stroke:#00897B,stroke-width:2px
    style Container fill:#C8E6C9,stroke:#388E3C,stroke-width:3px
Loading

Components

Component Description AWS Service Tier
Internet Gateway Connection between VPC and Internet EC2 Edge
VPC Isolated Network (10.0.0.0/16) EC2 Network
Public Subnet Network segment with IGW access (10.0.1.0/24) EC2 Network
Security Group Stateful Firewall (L4) - Port 80 allow EC2 Network
Elastic Network Interface Virtual Network Card with Public IP EC2 Network
ECS Cluster Container Orchestration Control Plane ECS Orchestration
ECS Service Managed Container Lifecycle Manager (desired: 1) ECS Orchestration
Task Definition Container Configuration Template (CPU: 256, RAM: 512) ECS Orchestration
AWS Fargate Serverless Container Runtime ECS Compute
Container nginx:latest Docker Image Fargate Application

Configure

aws configure
# AWS Access Key ID: [enter]
# AWS Secret Access Key: [enter]
# Default region: eu-central-1
# Output: json

Network Setup

# Create VPC
VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region eu-central-1 --query 'Vpc.VpcId' --output text)

# Create Subnet + enable public IPs
SUBNET_ID=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --availability-zone eu-central-1a --region eu-central-1 --query 'Subnet.SubnetId' --output text)
aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID --map-public-ip-on-launch --region eu-central-1

# Create Internet Gateway + attach
IGW_ID=$(aws ec2 create-internet-gateway --region eu-central-1 --query 'InternetGateway.InternetGatewayId' --output text)
aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID --region eu-central-1

# Add route to IGW
ROUTE_TABLE_ID=$(aws ec2 describe-route-tables --filters "Name=vpc-id,Values=$VPC_ID" --query 'RouteTables[0].RouteTableId' --output text --region eu-central-1)
aws ec2 create-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID --region eu-central-1

# Create Security Group + allow HTTP
SG_ID=$(aws ec2 create-security-group --group-name nginx-sg --description "Allow HTTP" --vpc-id $VPC_ID --region eu-central-1 --query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 80 --cidr 0.0.0.0/0 --region eu-central-1

# Verify
echo "VPC: $VPC_ID | Subnet: $SUBNET_ID | IGW: $IGW_ID | SG: $SG_ID"

ECS Setup

# Register Task Definition
aws ecs register-task-definition \
  --family my-server-family --network-mode awsvpc --requires-compatibilities FARGATE \
  --cpu 256 --memory 512 \
  --container-definitions '[{"name":"my-server","image":"nginx:latest","portMappings":[{"containerPort":80,"hostPort":80,"protocol":"tcp"}]}]' \
  --region eu-central-1

# Create Cluster
aws ecs create-cluster --cluster-name my-cluster --region eu-central-1

# Create Service
aws ecs create-service \
  --cluster my-cluster --service-name my-service \
  --task-definition my-server-family:1 --desired-count 1 --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[$SUBNET_ID],securityGroups=[$SG_ID],assignPublicIp=ENABLED}" \
  --region eu-central-1

Verify

# Get task ARN
TASK_ARN=$(aws ecs list-tasks --cluster my-cluster --desired-status RUNNING --region eu-central-1 --query 'taskArns[0]' --output text)

# Get ENI + Public IP
ENI_ID=$(aws ecs describe-tasks --cluster my-cluster --tasks $TASK_ARN --region eu-central-1 --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' --output text)
PUBLIC_IP=$(aws ec2 describe-network-interfaces --network-interface-ids $ENI_ID --region eu-central-1 --query 'NetworkInterfaces[0].Association.PublicIp' --output text)

# Test
curl http://$PUBLIC_IP
# Expected: HTTP 200 with NGINX welcome page

Cleanup

# Delete in order
aws ecs delete-service --cluster my-cluster --service my-service --force --region eu-central-1
aws ecs delete-cluster --cluster my-cluster --region eu-central-1
aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID --region eu-central-1
aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID --region eu-central-1
aws ec2 delete-security-group --group-id $SG_ID --region eu-central-1
aws ec2 delete-subnet --subnet-id $SUBNET_ID --region eu-central-1
aws ec2 delete-vpc --vpc-id $VPC_ID --region eu-central-1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment