[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C48D77PN2F3RN1B7AS0GRC":3,"skill-same:01M6C48D77PN2F3RN1B7AS0GRC":69},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":47,"commitSha":48,"skillDirectory":5,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":6,"ownerHtmlUrl":51,"ownerBlogUrl":52,"ownerDescription":53,"updatedAt":54,"install":55,"resources":68},"01M6C48D77PN2F3RN1B7AS0GRC","cloudflare-tunnel-ec2-deployment",null,"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.","stakpak\u002Fcommunity-paks","stakpak","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F86326525?v=4","01M6C48005ADA10YG0BQQX0J4Q","Stakpak","01M6C4804JD6KKZR9AQ9TYS0BT",4,"MIT","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fcloudflare-tunnel-ec2-deployment\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37],"deployment","cloudflare","ec2","cloudflare tunnel ec2 deployment","deploy","dev","https","ssl","aws","applications","certificates","team","ports","public","2026-11-10 10:12:30",false,"---\nname: cloudflare-tunnel-ec2-deployment\ndescription: |\n  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.\nlicense: MIT\nmetadata:\n  author: Stakpak \u003Cteam@stakpak.dev>\n  version: 1.0.17\n---\n\n# Deploying Applications on EC2 with Cloudflare Tunnel\n\n## Quick Start\n\n### Provision and Deploy\n\n```bash\n# Get VPC and subnet\nVPC_ID=$(aws ec2 describe-vpcs --filters \"Name=isDefault,Values=true\" --query 'Vpcs[0].VpcId' --output text)\nSUBNET_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)\n\n# Create security group\nSG_ID=$(aws ec2 create-security-group --group-name app-sg --description \"Security group for app deployment\" --vpc-id $VPC_ID --query 'GroupId' --output text)\naws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 22 --cidr 0.0.0.0\u002F0\n\n# Launch instance\nAMI_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)\nINSTANCE_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)\n```\n\n## Prerequisites\n\n* AWS CLI configured with appropriate permissions (EC2, VPC)\n* Cloudflare account with a domain configured\n* Docker-compatible application with Dockerfile\n* Cloudflare Tunnel token from Zero Trust dashboard\n\n## Infrastructure Setup\n\n### 1. VPC Resources\n\n```bash\n# Get default VPC\nVPC_ID=$(aws ec2 describe-vpcs --filters \"Name=isDefault,Values=true\" \\\n  --query 'Vpcs[0].VpcId' --output text)\n\n# Get public subnet\nSUBNET_ID=$(aws ec2 describe-subnets \\\n  --filters \"Name=vpc-id,Values=$VPC_ID\" \"Name=map-public-ip-on-launch,Values=true\" \\\n  --query 'Subnets[0].SubnetId' --output text)\n```\n\n### 2. Security Group\n\n```bash\n# Create security group - only SSH needed for management\n# Cloudflare Tunnel handles all inbound traffic\nSG_ID=$(aws ec2 create-security-group \\\n  --group-name app-sg \\\n  --description \"Security group for app deployment\" \\\n  --vpc-id $VPC_ID \\\n  --query 'GroupId' --output text)\n\n# Allow SSH access (restrict to your IP in production)\naws ec2 authorize-security-group-ingress \\\n  --group-id $SG_ID \\\n  --protocol tcp --port 22 --cidr 0.0.0.0\u002F0\n```\n\n**Key insight:** With Cloudflare Tunnel, you don't need to open ports 80\u002F443. The tunnel creates outbound connections to Cloudflare, eliminating inbound attack surface.\n\n### 3. SSH Key Pair\n\n```bash\n# Generate local key\nssh-keygen -t ed25519 -f ~\u002F.ssh\u002Fapp-deploy-key -N \"\" -C \"app-deploy\"\n\n# Import to AWS\naws ec2 import-key-pair \\\n  --key-name app-deploy-key \\\n  --public-key-material fileb:\u002F\u002F~\u002F.ssh\u002Fapp-deploy-key.pub\n```\n\n**Important:** Never delete SSH keys after creation - you'll be locked out of the instance.\n\n### 4. Launch EC2 Instance\n\n```bash\n# Get latest Amazon Linux 2023 AMI\nAMI_ID=$(aws ec2 describe-images --owners amazon \\\n  --filters \"Name=name,Values=al2023-ami-2023*-x86_64\" \"Name=state,Values=available\" \\\n  --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text)\n\n# Launch instance\nINSTANCE_ID=$(aws ec2 run-instances \\\n  --image-id $AMI_ID \\\n  --instance-type t3.small \\\n  --key-name app-deploy-key \\\n  --security-group-ids $SG_ID \\\n  --subnet-id $SUBNET_ID \\\n  --associate-public-ip-address \\\n  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-app}]' \\\n  --query 'Instances[0].InstanceId' --output text)\n\n# Wait for instance and get IP\naws ec2 wait instance-running --instance-ids $INSTANCE_ID\nPUBLIC_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \\\n  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)\n```\n\n### Instance Sizing\n\n| Instance Type | Use Case |\n|---------------|----------|\n| `t3.micro` | Simple static sites, minimal APIs |\n| `t3.small` | Standard web apps, Node.js\u002FPython services |\n| `t3.medium` | Apps with build steps, multiple containers |\n\n## Application Deployment\n\n### Install Docker\n\n```bash\n# Wait for SSH to be ready (30-60 seconds after instance running)\nsleep 45\n\n# Install Docker\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo dnf install -y docker git && \\\n   sudo systemctl enable --now docker && \\\n   sudo usermod -aG docker ec2-user\"\n```\n\n### Deploy Application\n\n```bash\n# Clone and build application\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"git clone \u003CREPO_URL> app && \\\n   cd app && \\\n   echo 'ENV_VAR=value' > .env\"\n\n# Build and run container\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"cd app && \\\n   sudo docker build -t myapp:latest . && \\\n   sudo docker run -d --name myapp --restart unless-stopped -p 80:80 myapp:latest\"\n```\n\n### Production Dockerfile Pattern\n\n```dockerfile\nFROM node:20-alpine AS builder\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nARG VITE_API_KEY\nENV VITE_API_KEY=$VITE_API_KEY\nRUN npm run build\n\nFROM nginx:alpine\nCOPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n```\n\n**Reasoning:** Multi-stage builds reduce image size and don't include build tools in production.\n\n## Cloudflare Tunnel Configuration\n\n### Install cloudflared\n\n```bash\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"curl -fsSL https:\u002F\u002Fpkg.cloudflare.com\u002Fcloudflared.repo | \\\n   sudo tee \u002Fetc\u002Fyum.repos.d\u002Fcloudflared.repo && \\\n   sudo yum install -y cloudflared\"\n```\n\n### Install Tunnel as Service\n\n```bash\n# Use the token from Cloudflare Zero Trust dashboard\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo cloudflared service install \u003CTUNNEL_TOKEN>\"\n```\n\n**Reasoning:** Installing as a systemd service ensures the tunnel auto-starts on reboot and restarts on failure.\n\n### Verify Tunnel Connection\n\n```bash\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo systemctl status cloudflared\"\n```\n\nLook for: `Registered tunnel connection` messages (should see 4 connections for a healthy tunnel).\n\n## DNS Configuration\n\n### Cloudflare Dashboard Method\n\nIn Cloudflare Zero Trust dashboard:\n1. Navigate to **Networks → Tunnels**\n2. Select your tunnel → **Public Hostname** tab\n3. Add hostname:\n   - Subdomain: `app`\n   - Domain: `example.com`\n   - Type: `HTTP`\n   - URL: `localhost:80`\n\nThis automatically creates a CNAME record pointing to `\u003Ctunnel-id>.cfargotunnel.com`.\n\n### API Method\n\n```bash\n# Create DNS record via API\ncurl -X POST \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fzones\u002F$ZONE_ID\u002Fdns_records\" \\\n  -H \"Authorization: Bearer $CF_API_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  --data '{\n    \"type\": \"CNAME\",\n    \"name\": \"app\",\n    \"content\": \"\u003Ctunnel-id>.cfargotunnel.com\",\n    \"proxied\": true\n  }'\n```\n\n## Validation\n\n### Test Deployment\n\n```bash\n# Test via tunnel (may take 1-2 minutes for DNS propagation)\ncurl -sI https:\u002F\u002Fapp.example.com\u002F\n\n# Check container logs\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo docker logs myapp\"\n\n# Verify tunnel health\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo journalctl -u cloudflared -n 20\"\n```\n\n### Success Criteria\n\n* HTTP 200 response from public URL\n* No errors in container logs\n* 4 registered tunnel connections\n\n## Outputs Documentation\n\nCreate an outputs file for future reference:\n\n```json\n{\n  \"app_url\": \"https:\u002F\u002Fapp.example.com\",\n  \"ec2_instance_id\": \"\u003Cinstance-id>\",\n  \"ec2_public_ip\": \"\u003Cpublic-ip>\",\n  \"aws_region\": \"us-east-1\",\n  \"ssh_command\": \"ssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@\u003Cpublic-ip>\",\n  \"cloudflare_tunnel_id\": \"\u003Ctunnel-id>\",\n  \"container_name\": \"myapp\"\n}\n```\n\n## Security Considerations\n\n* **Restrict SSH access** - Use specific IP ranges instead of 0.0.0.0\u002F0\n* **No public ports needed** - Cloudflare Tunnel eliminates need for ports 80\u002F443\n* **Rotate tunnel tokens** - If compromised, regenerate in Cloudflare dashboard\n* **Use secrets management** - Don't hardcode API keys in Dockerfiles; use build args or runtime env vars\n* **Enable Cloudflare Access** - Add authentication layer for sensitive applications\n\n## Troubleshooting\n\n| Issue | Diagnosis | Solution |\n|-------|-----------|----------|\n| DNS not resolving | `dig @1.1.1.1 app.example.com` | Wait for propagation or check CNAME record |\n| Tunnel not connecting | Check `systemctl status cloudflared` | Verify token, check outbound connectivity on port 7844 |\n| Container not starting | `docker logs myapp` | Check Dockerfile, environment variables |\n| 502 Bad Gateway | Tunnel running but app not responding | Verify container is listening on correct port |\n\n## References\n\n* [Cloudflare Tunnel Documentation](https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fnetworks\u002Fconnectors\u002Fcloudflare-tunnel\u002F)\n* [AWS EC2 User Guide](https:\u002F\u002Fdocs.aws.amazon.com\u002FAWSEC2\u002Flatest\u002FUserGuide\u002F)\n* [Docker Multi-stage Builds](https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-stage\u002F)","# Deploying Applications on EC2 with Cloudflare Tunnel\n\n## Quick Start\n\n### Provision and Deploy\n\n```bash\n# Get VPC and subnet\nVPC_ID=$(aws ec2 describe-vpcs --filters \"Name=isDefault,Values=true\" --query 'Vpcs[0].VpcId' --output text)\nSUBNET_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)\n\n# Create security group\nSG_ID=$(aws ec2 create-security-group --group-name app-sg --description \"Security group for app deployment\" --vpc-id $VPC_ID --query 'GroupId' --output text)\naws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 22 --cidr 0.0.0.0\u002F0\n\n# Launch instance\nAMI_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)\nINSTANCE_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)\n```\n\n## Prerequisites\n\n* AWS CLI configured with appropriate permissions (EC2, VPC)\n* Cloudflare account with a domain configured\n* Docker-compatible application with Dockerfile\n* Cloudflare Tunnel token from Zero Trust dashboard\n\n## Infrastructure Setup\n\n### 1. VPC Resources\n\n```bash\n# Get default VPC\nVPC_ID=$(aws ec2 describe-vpcs --filters \"Name=isDefault,Values=true\" \\\n  --query 'Vpcs[0].VpcId' --output text)\n\n# Get public subnet\nSUBNET_ID=$(aws ec2 describe-subnets \\\n  --filters \"Name=vpc-id,Values=$VPC_ID\" \"Name=map-public-ip-on-launch,Values=true\" \\\n  --query 'Subnets[0].SubnetId' --output text)\n```\n\n### 2. Security Group\n\n```bash\n# Create security group - only SSH needed for management\n# Cloudflare Tunnel handles all inbound traffic\nSG_ID=$(aws ec2 create-security-group \\\n  --group-name app-sg \\\n  --description \"Security group for app deployment\" \\\n  --vpc-id $VPC_ID \\\n  --query 'GroupId' --output text)\n\n# Allow SSH access (restrict to your IP in production)\naws ec2 authorize-security-group-ingress \\\n  --group-id $SG_ID \\\n  --protocol tcp --port 22 --cidr 0.0.0.0\u002F0\n```\n\n**Key insight:** With Cloudflare Tunnel, you don't need to open ports 80\u002F443. The tunnel creates outbound connections to Cloudflare, eliminating inbound attack surface.\n\n### 3. SSH Key Pair\n\n```bash\n# Generate local key\nssh-keygen -t ed25519 -f ~\u002F.ssh\u002Fapp-deploy-key -N \"\" -C \"app-deploy\"\n\n# Import to AWS\naws ec2 import-key-pair \\\n  --key-name app-deploy-key \\\n  --public-key-material fileb:\u002F\u002F~\u002F.ssh\u002Fapp-deploy-key.pub\n```\n\n**Important:** Never delete SSH keys after creation - you'll be locked out of the instance.\n\n### 4. Launch EC2 Instance\n\n```bash\n# Get latest Amazon Linux 2023 AMI\nAMI_ID=$(aws ec2 describe-images --owners amazon \\\n  --filters \"Name=name,Values=al2023-ami-2023*-x86_64\" \"Name=state,Values=available\" \\\n  --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text)\n\n# Launch instance\nINSTANCE_ID=$(aws ec2 run-instances \\\n  --image-id $AMI_ID \\\n  --instance-type t3.small \\\n  --key-name app-deploy-key \\\n  --security-group-ids $SG_ID \\\n  --subnet-id $SUBNET_ID \\\n  --associate-public-ip-address \\\n  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-app}]' \\\n  --query 'Instances[0].InstanceId' --output text)\n\n# Wait for instance and get IP\naws ec2 wait instance-running --instance-ids $INSTANCE_ID\nPUBLIC_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \\\n  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)\n```\n\n### Instance Sizing\n\n| Instance Type | Use Case |\n|---------------|----------|\n| `t3.micro` | Simple static sites, minimal APIs |\n| `t3.small` | Standard web apps, Node.js\u002FPython services |\n| `t3.medium` | Apps with build steps, multiple containers |\n\n## Application Deployment\n\n### Install Docker\n\n```bash\n# Wait for SSH to be ready (30-60 seconds after instance running)\nsleep 45\n\n# Install Docker\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo dnf install -y docker git && \\\n   sudo systemctl enable --now docker && \\\n   sudo usermod -aG docker ec2-user\"\n```\n\n### Deploy Application\n\n```bash\n# Clone and build application\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"git clone \u003CREPO_URL> app && \\\n   cd app && \\\n   echo 'ENV_VAR=value' > .env\"\n\n# Build and run container\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"cd app && \\\n   sudo docker build -t myapp:latest . && \\\n   sudo docker run -d --name myapp --restart unless-stopped -p 80:80 myapp:latest\"\n```\n\n### Production Dockerfile Pattern\n\n```dockerfile\nFROM node:20-alpine AS builder\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nARG VITE_API_KEY\nENV VITE_API_KEY=$VITE_API_KEY\nRUN npm run build\n\nFROM nginx:alpine\nCOPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n```\n\n**Reasoning:** Multi-stage builds reduce image size and don't include build tools in production.\n\n## Cloudflare Tunnel Configuration\n\n### Install cloudflared\n\n```bash\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"curl -fsSL https:\u002F\u002Fpkg.cloudflare.com\u002Fcloudflared.repo | \\\n   sudo tee \u002Fetc\u002Fyum.repos.d\u002Fcloudflared.repo && \\\n   sudo yum install -y cloudflared\"\n```\n\n### Install Tunnel as Service\n\n```bash\n# Use the token from Cloudflare Zero Trust dashboard\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo cloudflared service install \u003CTUNNEL_TOKEN>\"\n```\n\n**Reasoning:** Installing as a systemd service ensures the tunnel auto-starts on reboot and restarts on failure.\n\n### Verify Tunnel Connection\n\n```bash\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo systemctl status cloudflared\"\n```\n\nLook for: `Registered tunnel connection` messages (should see 4 connections for a healthy tunnel).\n\n## DNS Configuration\n\n### Cloudflare Dashboard Method\n\nIn Cloudflare Zero Trust dashboard:\n1. Navigate to **Networks → Tunnels**\n2. Select your tunnel → **Public Hostname** tab\n3. Add hostname:\n   - Subdomain: `app`\n   - Domain: `example.com`\n   - Type: `HTTP`\n   - URL: `localhost:80`\n\nThis automatically creates a CNAME record pointing to `\u003Ctunnel-id>.cfargotunnel.com`.\n\n### API Method\n\n```bash\n# Create DNS record via API\ncurl -X POST \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fzones\u002F$ZONE_ID\u002Fdns_records\" \\\n  -H \"Authorization: Bearer $CF_API_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  --data '{\n    \"type\": \"CNAME\",\n    \"name\": \"app\",\n    \"content\": \"\u003Ctunnel-id>.cfargotunnel.com\",\n    \"proxied\": true\n  }'\n```\n\n## Validation\n\n### Test Deployment\n\n```bash\n# Test via tunnel (may take 1-2 minutes for DNS propagation)\ncurl -sI https:\u002F\u002Fapp.example.com\u002F\n\n# Check container logs\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo docker logs myapp\"\n\n# Verify tunnel health\nssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@$PUBLIC_IP \\\n  \"sudo journalctl -u cloudflared -n 20\"\n```\n\n### Success Criteria\n\n* HTTP 200 response from public URL\n* No errors in container logs\n* 4 registered tunnel connections\n\n## Outputs Documentation\n\nCreate an outputs file for future reference:\n\n```json\n{\n  \"app_url\": \"https:\u002F\u002Fapp.example.com\",\n  \"ec2_instance_id\": \"\u003Cinstance-id>\",\n  \"ec2_public_ip\": \"\u003Cpublic-ip>\",\n  \"aws_region\": \"us-east-1\",\n  \"ssh_command\": \"ssh -i ~\u002F.ssh\u002Fapp-deploy-key ec2-user@\u003Cpublic-ip>\",\n  \"cloudflare_tunnel_id\": \"\u003Ctunnel-id>\",\n  \"container_name\": \"myapp\"\n}\n```\n\n## Security Considerations\n\n* **Restrict SSH access** - Use specific IP ranges instead of 0.0.0.0\u002F0\n* **No public ports needed** - Cloudflare Tunnel eliminates need for ports 80\u002F443\n* **Rotate tunnel tokens** - If compromised, regenerate in Cloudflare dashboard\n* **Use secrets management** - Don't hardcode API keys in Dockerfiles; use build args or runtime env vars\n* **Enable Cloudflare Access** - Add authentication layer for sensitive applications\n\n## Troubleshooting\n\n| Issue | Diagnosis | Solution |\n|-------|-----------|----------|\n| DNS not resolving | `dig @1.1.1.1 app.example.com` | Wait for propagation or check CNAME record |\n| Tunnel not connecting | Check `systemctl status cloudflared` | Verify token, check outbound connectivity on port 7844 |\n| Container not starting | `docker logs myapp` | Check Dockerfile, environment variables |\n| 502 Bad Gateway | Tunnel running but app not responding | Verify container is listening on correct port |\n\n## References\n\n* [Cloudflare Tunnel Documentation](https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fnetworks\u002Fconnectors\u002Fcloudflare-tunnel\u002F)\n* [AWS EC2 User Guide](https:\u002F\u002Fdocs.aws.amazon.com\u002FAWSEC2\u002Flatest\u002FUserGuide\u002F)\n* [Docker Multi-stage Builds](https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-stage\u002F)",{"name":5,"license":15,"metadata":43,"description":46},{"author":44,"version":45},"Stakpak \u003Cteam@stakpak.dev>","1.0.17","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.\n","main","d9bbde9885439c55adad930456b2660b0c37c052",1,"https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks","https:\u002F\u002Fgithub.com\u002Fstakpak","https:\u002F\u002Fwww.stakpak.dev","AI that runs your Infra","2026-07-04 20:18:32",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add stakpak\u002Fcommunity-paks --skill cloudflare-tunnel-ec2-deployment",{"tool":61,"command":62},"bunx","bunx skills add stakpak\u002Fcommunity-paks --skill cloudflare-tunnel-ec2-deployment",{"tool":64,"command":65},"pnpm","pnpm dlx skills add stakpak\u002Fcommunity-paks --skill cloudflare-tunnel-ec2-deployment","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fcloudflare-tunnel-ec2-deployment\u002FSKILL.md",true,[],[70,101,125,141,160,178],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":85,"publishedAt":38},"01M6C49TTAVC8Q9CTTC05F6VSR","vllm-deployment","Deploy vLLM for high-performance LLM inference. Covers Docker CPU\u002FGPU deployments and cloud VM provisioning with OpenAI-compatible API endpoints.","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fvllm-deployment\u002FSKILL.md",[76,79,80],{"categoryNo":77,"categoryName":78,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[86,87,24,88,89,90,91,92,35,93,94,95,96,97,29,98,28,99,100],"vllm deployment","vLLM","docker","cloud","openai-api","llm inference","learning","api","provisioning","machine-learning","gpu","openai","vm","performance","inference",{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":108,"publishedAt":38},"01M6C49R31XN7KJ7Y0Y78XVYTQ","terrateam-usage-guide","A comprehensive guide for configuring and using Terrateam, an open-source GitOps CI\u002FCD platform for Terraform and OpenTofu. Covers configuration file structure, access control, workflows, OIDC authentication, drift detection, and best practices for managing infrastructure through pull requests.","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fterrateam-usage-guide\u002FSKILL.md",[107],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[109,110,111,112,113,35,114,115,116,117,118,29,119,120,121,122,123,124],"terrateam usage guide","guide","file","opentofu","access","open","detection","oidc","ci","pull","terraform","best practices","authentication","infrastructure","pull requests","workflows",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":38},"01M6C49N78AMM570EGPDXEZZDY","simple-deployment-on-vm","How to do simple but secure deployments using virtual machines on different cloud providers","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fsimple-deployment-on-vm\u002FSKILL.md",[],[132,98,24,133,29,134,135,35,26,136,137,32,138,89,139,28,140],"simple deployment on vm","tls configuration","virtual","how","Providers","tls","dns","secure","security",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":38},"01M6C49J8PRVT623JWRTTKFNJV","nextjs-on-aws","This document compares various AWS deployment options for Next.js applications, analyzing costs, benefits, limitations, and providing recommendations based on different use cases.","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fnextjs-on-aws\u002FSKILL.md",[],[148,32,149,150,151,152,35,153,154,33,155,156,29,24,157,158,159],"nextjs on aws","nextjs","use","aws deployment","js","Next.js","analysis","analyzing","cost","architecture","migration","cost-analysis",{"skillNo":161,"name":162,"nameZh":6,"description":163,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":164,"categories":165,"keywords":166,"publishedAt":38},"01M6C49F5B4BF2CHNT4X08XP69","migrating-bitnami-to-bitnami-legacy","This rule book helps you migrate Bitnami Helm charts and container images from the bitnami repository to the bitnamilegacy repository.\n\nThis migration is necessary due to Bitnami's transition, effective August 28th, 2025, where existing images will be moved to the legacy repo","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fmigrating-bitnami-to-bitnami-legacy\u002FSKILL.md",[],[167,168,35,169,170,171,172,173,174,175,29,176,177],"migrating bitnami to bitnami legacy","container images","helm","migrate","bitnami-helm-charts","bitnami-legacy","bitnami","container","repo","repository","Charts",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":184,"publishedAt":38},"01M6C49CHCPGZZ42P5W1MTV3WS","k3s-backup","Backup and recovery solution for K3s clusters. Includes scheduled, pre-shutdown, and manual backup strategies with recovery procedures.","https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fcommunity-paks\u002Fblob\u002Fmain\u002Fk3s-backup\u002FSKILL.md",[],[185,186,187,29,188,35],"backup","k3s","k3s backup","recovery"]