본문으로 건너뛰기
cccskills
무료GitHub에 공개

cloudflare-tunnel-ec2-deployment

Deploy containerized applications to AWS EC2 and expose them publicly via Cloudflare Tunnel with automatic HTTPS. Eliminates need for load balancers, SSL certificates, or public inbound ports.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구CloudflareAWSDocker
설치 방법 보기

포함된 파일(2)

  • SKILL.md8.9 KB
  • CONCOMITANT_SKILLS.md1.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Deploying Applications on EC2 with Cloudflare Tunnel

Quick Start

Provision and Deploy

# Get VPC and subnet
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=isDefault,Values=true" --query 'Vpcs[0].VpcId' --output text)
SUBNET_ID=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPC_ID" "Name=map-public-ip-on-launch,Values=true" --query 'Subnets[0].SubnetId' --output text)

# Create security group
SG_ID=$(aws ec2 create-security-group --group-name app-sg --description "Security group for app deployment" --vpc-id $VPC_ID --query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 22 --cidr 0.0.0.0/0

# Launch instance
AMI_ID=$(aws ec2 describe-images --owners amazon --filters "Name=name,Values=al2023-ami-2023*-x86_64" "Name=state,Values=available" --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text)
INSTANCE_ID=$(aws ec2 run-instances --image-id $AMI_ID --instance-type t3.small --key-name app-deploy-key --security-group-ids $SG_ID --subnet-id $SUBNET_ID --associate-public-ip-address --query 'Instances[0].InstanceId' --output text)

Prerequisites

  • AWS CLI configured with appropriate permissions (EC2, VPC)
  • Cloudflare account with a domain configured
  • Docker-compatible application with Dockerfile
  • Cloudflare Tunnel token from Zero Trust dashboard

Infrastructure Setup

1. VPC Resources

# Get default VPC
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=isDefault,Values=true" \
  --query 'Vpcs[0].VpcId' --output text)

# Get public subnet
SUBNET_ID=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=$VPC_ID" "Name=map-public-ip-on-launch,Values=true" \
  --query 'Subnets[0].SubnetId' --output text)

2. Security Group

# Create security group - only SSH needed for management
# Cloudflare Tunnel handles all inbound traffic
SG_ID=$(aws ec2 create-security-group \
  --group-name app-sg \
  --description "Security group for app deployment" \
  --vpc-id $VPC_ID \
  --query 'GroupId' --output text)

# Allow SSH access (restrict to your IP in production)
aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --protocol tcp --port 22 --cidr 0.0.0.0/0

Key insight: With Cloudflare Tunnel, you don't need to open ports 80/443. The tunnel creates outbound connections to Cloudflare, eliminating inbound attack surface.

3. SSH Key Pair

# Generate local key
ssh-keygen -t ed25519 -f ~/.ssh/app-deploy-key -N "" -C "app-deploy"

# Import to AWS
aws ec2 import-key-pair \
  --key-name app-deploy-key \
  --public-key-material fileb://~/.ssh/app-deploy-key.pub

Important: Never delete SSH keys after creation - you'll be locked out of the instance.

4. Launch EC2 Instance

# Get latest Amazon Linux 2023 AMI
AMI_ID=$(aws ec2 describe-images --owners amazon \
  --filters "Name=name,Values=al2023-ami-2023*-x86_64" "Name=state,Values=available" \
  --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text)

# Launch instance
INSTANCE_ID=$(aws ec2 run-instances \
  --image-id $AMI_ID \
  --instance-type t3.small \
  --key-name app-deploy-key \
  --security-group-ids $SG_ID \
  --subnet-id $SUBNET_ID \
  --associate-public-ip-address \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-app}]' \
  --query 'Instances[0].InstanceId' --output text)

# Wait for instance and get IP
aws ec2 wait instance-running --instance-ids $INSTANCE_ID
PUBLIC_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \
  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)

Instance Sizing

Instance TypeUse Case
t3.microSimple static sites, minimal APIs
t3.smallStandard web apps, Node.js/Python services
t3.mediumApps with build steps, multiple containers

Application Deployment

Install Docker

# Wait for SSH to be ready (30-60 seconds after instance running)
sleep 45

# Install Docker
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "sudo dnf install -y docker git && \
   sudo systemctl enable --now docker && \
   sudo usermod -aG docker ec2-user"

Deploy Application

# Clone and build application
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "git clone <REPO_URL> app && \
   cd app && \
   echo 'ENV_VAR=value' > .env"

# Build and run container
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "cd app && \
   sudo docker build -t myapp:latest . && \
   sudo docker run -d --name myapp --restart unless-stopped -p 80:80 myapp:latest"

Production Dockerfile Pattern

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_API_KEY
ENV VITE_API_KEY=$VITE_API_KEY
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Reasoning: Multi-stage builds reduce image size and don't include build tools in production.

Cloudflare Tunnel Configuration

Install cloudflared

ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "curl -fsSL https://pkg.cloudflare.com/cloudflared.repo | \
   sudo tee /etc/yum.repos.d/cloudflared.repo && \
   sudo yum install -y cloudflared"

Install Tunnel as Service

# Use the token from Cloudflare Zero Trust dashboard
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "sudo cloudflared service install <TUNNEL_TOKEN>"

Reasoning: Installing as a systemd service ensures the tunnel auto-starts on reboot and restarts on failure.

Verify Tunnel Connection

ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "sudo systemctl status cloudflared"

Look for: Registered tunnel connection messages (should see 4 connections for a healthy tunnel).

DNS Configuration

Cloudflare Dashboard Method

In Cloudflare Zero Trust dashboard:

  1. Navigate to Networks → Tunnels
  2. Select your tunnel → Public Hostname tab
  3. Add hostname:
    • Subdomain: app
    • Domain: example.com
    • Type: HTTP
    • URL: localhost:80

This automatically creates a CNAME record pointing to <tunnel-id>.cfargotunnel.com.

API Method

# Create DNS record via API
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "app",
    "content": "<tunnel-id>.cfargotunnel.com",
    "proxied": true
  }'

Validation

Test Deployment

# Test via tunnel (may take 1-2 minutes for DNS propagation)
curl -sI https://app.example.com/

# Check container logs
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "sudo docker logs myapp"

# Verify tunnel health
ssh -i ~/.ssh/app-deploy-key ec2-user@$PUBLIC_IP \
  "sudo journalctl -u cloudflared -n 20"

Success Criteria

  • HTTP 200 response from public URL
  • No errors in container logs
  • 4 registered tunnel connections

Outputs Documentation

Create an outputs file for future reference:

{
  "app_url": "https://app.example.com",
  "ec2_instance_id": "<instance-id>",
  "ec2_public_ip": "<public-ip>",
  "aws_region": "us-east-1",
  "ssh_command": "ssh -i ~/.ssh/app-deploy-key ec2-user@<public-ip>",
  "cloudflare_tunnel_id": "<tunnel-id>",
  "container_name": "myapp"
}

Security Considerations

  • Restrict SSH access - Use specific IP ranges instead of 0.0.0.0/0
  • No public ports needed - Cloudflare Tunnel eliminates need for ports 80/443
  • Rotate tunnel tokens - If compromised, regenerate in Cloudflare dashboard
  • Use secrets management - Don't hardcode API keys in Dockerfiles; use build args or runtime env vars
  • Enable Cloudflare Access - Add authentication layer for sensitive applications

Troubleshooting

IssueDiagnosisSolution
DNS not resolvingdig @1.1.1.1 app.example.comWait for propagation or check CNAME record
Tunnel not connectingCheck systemctl status cloudflaredVerify token, check outbound connectivity on port 7844
Container not startingdocker logs myappCheck Dockerfile, environment variables
502 Bad GatewayTunnel running but app not respondingVerify container is listening on correct port

References

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Model ElevenLabs voice synthesis as an ACSet schema with Unison ability handlers for typed voice operations. Use when integrating ElevenLabs TTS into category-theoretic pipelines, building typed voice synthesis workflows, or managing multi-voice narration with GF(3) conservation.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

Systematic process for analyzing and modernizing legacy applications to comply with the 12-Factor App methodology. Covers code analysis, configuration externalization, dependency management, and container/Kubernetes best practices.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

13c0e3

무료

Gay MCP skill at invocation 26

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

19d57d

무료

Gay MCP skill at invocation 5

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

1ea91a

무료

Gay MCP skill at invocation 27

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

1eab21

무료

Gay MCP skill at invocation 3

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

plurigrid/asi702026년 7월 10일 업데이트

plurigrid의 스킬 모두 보기

이 스킬의 문제 신고