Skip to content

Networking, Elastic IP & Route53 DNS

Comprehensive network control for your compute infrastructure: static Elastic IPs, dynamic firewall security groups, and native Amazon Route53 hosted DNS management.


Architecture Overview

This diagram illustrates how FOTOhub compute instances interact with VPCs, Security Groups, Elastic IPs, Route53, and external CDNs like Cloudflare.

mermaid
flowchart TD
    Internet((Internet)) --> CF[Cloudflare CDN / WAF]
    CF --> R53[Amazon Route53 DNS]
    Internet --> R53
    
    R53 -->|A Record| EIP[Elastic IP 18.197.82.14]
    
    subgraph Frankfurt VPC 172.31.0.0/16
        subgraph Public Subnet eu-central-1a
            EIP --> IGW[Internet Gateway]
            IGW --> ENI[Elastic Network Interface]
            
            subgraph Security Group sg-0abcdef123
                ENI -->|Allow 80/443| Node[FOTOhub Compute Instance]
            end
        end
        
        subgraph Private Subnet eu-central-1b
            Node <-->|VPC Peering| DB[(Private Database)]
        end
    end

Architecture Defaults

All resources default to the eu-central-1 (Frankfurt) region unless specified otherwise.


Elastic IP (Static Public IP)

By default, EC2 instances receive dynamic public IP addresses that change when the instance is stopped and started. Assigning an Elastic IP provides a persistent public IPv4 address that remains identical across reboots and power cycles.

1. Allocate & Attach Elastic IP

bash
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"region": "eu-central-1"}'
python
import os
import requests

api_key = os.getenv("FOTOHUB_API_KEY", "fh_live_YOUR_API_KEY")
url = "https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip"

response = requests.post(
    url,
    headers={"Authorization": f"Bearer {api_key}"},
    json={"region": "eu-central-1"}
)
print(response.json())
typescript
import fetch from "node-fetch";

const allocateEIP = async () => {
  const res = await fetch("https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip", {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_YOUR_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ region: "eu-central-1" })
  });
  const data = await res.json();
  console.log(data);
};

allocateEIP();
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	url := "https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip"
	payload := map[string]string{"region": "eu-central-1"}
	jsonValue, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
	req.Header.Set("Authorization", "Bearer fh_live_YOUR_API_KEY")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()
	fmt.Println("EIP Allocated")
}

Response:

json
{
  "allocation_id": "eipalloc-01928374a5b6",
  "public_ip": "18.197.82.14",
  "association_id": "eipassoc-0a1b2c3d4e5f",
  "instance_id": "inst_90f23b",
  "status": "associated"
}

Pricing Alert

Elastic IPs cost $0.005/hr when associated with a running instance, and $0.005/hr when idle (allocated but not associated). Be sure to release them when no longer needed!

2. Release Elastic IP

bash
curl -X DELETE https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"
python
import requests

requests.delete(
    "https://apis.fotohub.app/compute/v1/instances/inst_90f23b/elastic-ip",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}
)

VPC & Subnet Reference

Compute instances can be provisioned into private Virtual Private Clouds (VPCs) to ensure inter-node traffic flows over encrypted AWS backbones.

Production Network Details

  • VPC ID: vpc-08528c7005fc7f9d5
  • VPC CIDR: 172.31.0.0/16
  • Subnets (AZs): eu-central-1a, eu-central-1b, eu-central-1c

Listing VPCs

bash
curl -X GET https://apis.fotohub.app/compute/v1/aws/vpcs \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"
python
import requests
res = requests.get("https://apis.fotohub.app/compute/v1/aws/vpcs", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"})
print(res.json())

Listing Subnets

bash
curl -X GET "https://apis.fotohub.app/compute/v1/aws/subnets?vpc_id=vpc-08528c7005fc7f9d5" \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"
python
import requests
res = requests.get("https://apis.fotohub.app/compute/v1/aws/subnets?vpc_id=vpc-08528c7005fc7f9d5", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"})
print(res.json())

Dynamic Security Group Rules (Firewall)

Control inbound and outbound network access with granular CIDR rules. Each instance supports up to 20 rules.

Complete Security Group API

List Security Groups

bash
curl -X GET https://apis.fotohub.app/compute/v1/aws/security-groups \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Create Security Group

bash
curl -X POST https://apis.fotohub.app/compute/v1/aws/security-groups \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"name": "api-sg", "description": "API nodes", "vpc_id": "vpc-08528c7005fc7f9d5"}'

Delete Security Group

bash
curl -X DELETE https://apis.fotohub.app/compute/v1/aws/security-groups/sg-0abcdef123 \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

List SGs on Instance

bash
curl -X GET https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-groups \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Adding Inbound Rules

Open a port for a web service (e.g. port 8000 for FastAPI / vLLM):

bash
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "direction": "inbound",
    "protocol": "tcp",
    "port": 8000,
    "cidr": "0.0.0.0/0",
    "description": "Public vLLM API Access"
  }'
python
import requests

requests.post(
    "https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={
        "direction": "inbound",
        "protocol": "tcp",
        "port": 8000,
        "cidr": "0.0.0.0/0",
        "description": "Public vLLM API Access"
    }
)

Removing Rules

bash
curl -X DELETE https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"direction": "inbound", "protocol": "tcp", "port": 8000, "cidr": "0.0.0.0/0"}'

Route53 DNS Management

The compute engine provides full programmatic management over Amazon Route53 hosted zones and DNS records.

Complete DNS API

List Hosted Zones

bash
curl -X GET https://apis.fotohub.app/compute/v1/dns/zones \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Create Hosted Zone

bash
curl -X POST https://apis.fotohub.app/compute/v1/dns/zones \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"domain_name": "ai-models.yourcompany.com", "comment": "Inference endpoint domain"}'

Get Zone Details (NS Records)

bash
curl -X GET https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829 \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Verify Domain Ownership

bash
curl -X POST https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829/verify \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

List Records

bash
curl -X GET https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829/records \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Add Record

bash
curl -X POST https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829/records \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"name": "api", "type": "A", "value": "18.197.82.14", "ttl": 300}'

Delete Record

bash
curl -X DELETE https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829/records \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"name": "api", "type": "A"}'

Delete Zone

bash
curl -X DELETE https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829 \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY"

Domain Mapping Patterns

Automatically create an A record linking your instance's current public IP to your custom subdomain.

bash
# Add mapping
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/domain \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"subdomain": "api.myapp.com"}'

# Remove mapping
curl -X DELETE https://apis.fotohub.app/compute/v1/instances/inst_90f23b/domain \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -d '{"subdomain": "api.myapp.com"}'
python
import requests

# Add mapping
requests.post(
    "https://apis.fotohub.app/compute/v1/instances/inst_90f23b/domain",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"subdomain": "api.myapp.com"}
)

Automated MX Email Record Setup

Configure Google Workspace or ProtonMail MX records in a single API call:

bash
curl -X POST https://apis.fotohub.app/compute/v1/dns/zones/Z01928374829/setup-email \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"provider": "google"}'

This automatically adds required MX, SPF, and DKIM records for email validation.


Automated SSL/TLS Certificates with Certbot

Once your custom domain resolves to your instance's Elastic IP, secure it with free, auto-renewing TLS certificates from Let's Encrypt:

bash
# SSH into your instance using allocated Elastic IP
ssh -i worker.pem [email protected]

# 1. Install Certbot and Nginx plugin (or use the nginx-certbot preset)
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx

# 2. Obtain and install certificate in one command
sudo certbot --nginx -d comfy.ai-models.yourcompany.com --non-interactive --agree-tos -m [email protected]

# 3. Verify auto-renewal timer
sudo systemctl status certbot.timer

Zero-Trust Network Security

Enterprise machine learning clusters handling confidential user data require strict Zero-Trust network isolation. In this model, GPU instances are provisioned without public IPv4 addresses, all public internet ingress is blocked, and communications travel across encrypted point-to-point tunnels and private cloud backbones.

Key Tenets

  • Air-gapped private instances (assign_public_ip: false).
  • AWS PrivateLink for internal API access.
  • WireGuard mesh configuration (ChaCha20-Poly1305, MTU 1420).
mermaid
flowchart TD
    subgraph Enterprise On-Prem / Cloud VPC 10.100.0.0/16
        CorpClient["Enterprise ML Workstation"]
        InternalDB["Customer Data Warehouse"]
    end

    subgraph AWS Backbone Peering pcx-01928374a5b6
        CorpClient <-->|Zero Egress AWS Peering| PrivateALB
    end

    subgraph FOTOhub Compute Private VPC 172.31.0.0/16
        PrivateALB["Internal Application Load Balancer"]
        
        subgraph Air-Gapped GPU Compute Subnet
            Node1["GPU Worker 1<br/>No Public IP"]
            Node2["GPU Worker 2<br/>No Public IP"]
        end
        
        subgraph Kernel WireGuard Mesh wg0 - 10.42.0.0/24
            WG_Gateway["WireGuard Hub Node"]
            WG_Node1["WG Peer Node 1"]
            WG_Node2["WG Peer Node 2"]
        end
        
        PrivateLink["AWS PrivateLink Interface Endpoints"]
    end

    PrivateALB --> Node1 & Node2
    Node1 & Node2 <--> PrivateLink
    PrivateLink <--> S3Service["FOTOhub S3 (s1.fotohub.app)"]
    CorpClient <-.->|Encrypted ChaCha20-Poly1305 Tunnel| WG_Gateway

1. Inter-VPC Peering Connection

Connect your enterprise AWS account directly to your FOTOhub Compute VPC in Frankfurt (eu-central-1). Traffic routes over AWS fiber without traversing the public internet.

bash
curl -X POST https://apis.fotohub.app/compute/v1/aws/vpc-peering \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "peer_vpc_id": "vpc-0182938475a",
    "peer_owner_id": "123456789012",
    "peer_region": "eu-central-1",
    "name": "enterprise-corp-peering"
  }'
python
import requests

requests.post(
    "https://apis.fotohub.app/compute/v1/aws/vpc-peering",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={
        "peer_vpc_id": "vpc-0182938475a",
        "peer_owner_id": "123456789012",
        "peer_region": "eu-central-1",
        "name": "enterprise-corp-peering"
    }
)

2. High-Performance WireGuard Mesh Network

WireGuard provides kernel-level, ChaCha20-Poly1305 encrypted point-to-point tunnels with virtually zero CPU overhead and maximum MTU utilization (1420).

bash
#!/bin/bash
# /etc/wireguard/setup-mesh.sh
set -e

apt-get update && apt-get install -y wireguard wireguard-tools
umask 077
wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key
PRIVATE_KEY=$(cat /etc/wireguard/private.key)

cat > /etc/wireguard/wg0.conf << WGE_EOF
[Interface]
Address = 10.42.0.14/24
PrivateKey = ${PRIVATE_KEY}
ListenPort = 51820
MTU = 1420

[Peer]
PublicKey = 8kK/12A98...corp_pub_key...=
AllowedIPs = 10.42.0.1/32, 10.100.0.0/16
Endpoint = vpn.yourbrand.com:51820
PersistentKeepalive = 25
WGE_EOF

systemctl enable --now wg-quick@wg0

Standard AI Port Reference

Ensure you open the right ports via the Security Rules API for your AI workloads.

PortProtocolDefault ServiceRecommended Inbound Rule
22TCPOpenSSH Remote AdministrationRestrict to corporate VPN / static CIDR
80 / 443TCPNginx Web Server & TLS Proxy0.0.0.0/0 (Public)
3000TCPOpen WebUIInternal VPC or SSH tunnel
5432TCPPostgreSQL DatabaseStrict internal VPC binding
6379TCPRedis Distributed QueueStrict internal VPC binding
7860TCPGradio / Automatic1111 WebUIReverse proxy or SSH tunnel
8000TCPvLLM / SGLang OpenAI API ServerProtected via Nginx reverse proxy + API key
8080TCPGeneral API ServerSpecific CIDR or Public
8188TCPComfyUI WebSocket & REST APIInternal VPC or password-protected
9100TCPPrometheus Node ExporterScraped by internal monitoring subnet
11434TCPOllama Model RuntimeInternal localhost or VPC

Troubleshooting

SSH Connection Refused

Symptom: ssh: connect to host 18.197.82.14 port 22: Connection refused or timeout. Resolution: Verify your Security Group rules. By default, instances are locked down. You must explicitly allow Port 22 inbound from your IP address via the POST /instances/:id/security-rules endpoint.

Domain Not Resolving

Symptom: Browsing to api.myapp.com shows ERR_NAME_NOT_RESOLVED. Resolution: DNS propagation can take up to 24 hours globally, but usually updates in minutes. Verify your name servers at your registrar point to the FOTOhub/AWS Route53 name servers provided by the GET /dns/zones/:id response. Use dig api.myapp.com +trace to debug DNS delegation.

Elastic IP Not Reachable

Symptom: You allocated an EIP but the instance is unresponsive. Resolution: Verify the EIP association status is associated using GET /instances/:id/elastic-ip. Ensure the instance is running and has completed its boot sequence. Also check that your Security Group permits inbound traffic on the ports you are testing.


Advanced Networking Walkthroughs

1. Setting up a High-Availability Load Balancer with Auto-Scaling

When traffic to your LLM or ComfyUI instances spikes, you can distribute the load using a combination of Route53 weighted records and FOTOhub load balancers.

  1. Deploy multiple identical instances across different Availability Zones (e.g., eu-central-1a and eu-central-1b).
  2. Allocate Elastic IPs for each instance.
  3. Configure Route53 with weighted or latency-based routing policies pointing to the different EIPs.
python
import requests

# Deploy Instance 1 in AZ a
res1 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1a"}
)
inst1 = res1.json()["id"]

# Deploy Instance 2 in AZ b
res2 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1b"}
)
inst2 = res2.json()["id"]

# Allocate EIPs
eip1 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst1}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()
eip2 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst2}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()

print(f"Node 1 IP: {eip1['public_ip']}, Node 2 IP: {eip2['public_ip']}")

2. Implementing a Bastion Host (Jump Box)

For maximum security, avoid assigning Elastic IPs to your expensive GPU nodes. Instead, deploy a tiny CPU instance (e.g., t3.micro) as a Bastion host in a public subnet, and place your GPU instances in a private subnet.

  1. Create a t3.micro instance in the public subnet (eu-central-1a).
  2. Assign an Elastic IP to the Bastion host.
  3. Open Port 22 on the Bastion host to your office IP.
  4. Create a GPU instance in the private subnet without an Elastic IP.
  5. Open Port 22 on the GPU instance, allowing access only from the Bastion host's internal private IP.

To connect:

bash
# Connect to the Bastion host using SSH Agent Forwarding
ssh -A -i bastion.pem ubuntu@BASTION_EIP

# From within the Bastion, connect to the internal GPU node
ssh -i worker.pem ubuntu@GPU_PRIVATE_IP

3. Rate Limiting and WAF Integration

When using Route53, it is highly recommended to proxy your web traffic through a CDN and Web Application Firewall (WAF) like Cloudflare.

  1. In Cloudflare, add your domain.
  2. Configure your Route53 name servers to the ones provided by Cloudflare.
  3. In Cloudflare's DNS settings, create an A record pointing to your FOTOhub Elastic IP.
  4. Enable the "Proxy" status (orange cloud) in Cloudflare.
  5. In your FOTOhub Security Group, restrict Port 80 and 443 inbound traffic to only allow Cloudflare's published IP ranges.
bash
# Example: Adding a Cloudflare IP range to your Security Group
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "direction": "inbound",
    "protocol": "tcp",
    "port": 443,
    "cidr": "173.245.48.0/20",
    "description": "Cloudflare WAF Proxy"
  }'

By doing this, you ensure that malicious actors cannot bypass your WAF by connecting directly to your Elastic IP. All traffic is forced through Cloudflare's DDoS protection and rate limiting.

4. Continuous DNS Verification

If you are programmatically provisioning and destroying environments (e.g., in a CI/CD pipeline), you can use the DNS Verify endpoint to ensure your records have propagated before running integration tests.

python
import time
import requests

def wait_for_dns_propagation(zone_id, domain, timeout=600):
    start_time = time.time()
    while time.time() - start_time < timeout:
        res = requests.post(
            f"https://apis.fotohub.app/compute/v1/dns/zones/{zone_id}/verify",
            headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}
        )
        if res.json().get("status") == "verified":
            print(f"Domain {domain} successfully verified and propagated!")
            return True
        print("Waiting for DNS propagation...")
        time.sleep(30)
    raise TimeoutError("DNS propagation timed out.")

Advanced Networking Walkthroughs

1. Setting up a High-Availability Load Balancer with Auto-Scaling

When traffic to your LLM or ComfyUI instances spikes, you can distribute the load using a combination of Route53 weighted records and FOTOhub load balancers.

  1. Deploy multiple identical instances across different Availability Zones (e.g., eu-central-1a and eu-central-1b).
  2. Allocate Elastic IPs for each instance.
  3. Configure Route53 with weighted or latency-based routing policies pointing to the different EIPs.
python
import requests

# Deploy Instance 1 in AZ a
res1 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1a"}
)
inst1 = res1.json()["id"]

# Deploy Instance 2 in AZ b
res2 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1b"}
)
inst2 = res2.json()["id"]

# Allocate EIPs
eip1 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst1}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()
eip2 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst2}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()

print(f"Node 1 IP: {eip1['public_ip']}, Node 2 IP: {eip2['public_ip']}")

2. Implementing a Bastion Host (Jump Box)

For maximum security, avoid assigning Elastic IPs to your expensive GPU nodes. Instead, deploy a tiny CPU instance (e.g., t3.micro) as a Bastion host in a public subnet, and place your GPU instances in a private subnet.

  1. Create a t3.micro instance in the public subnet (eu-central-1a).
  2. Assign an Elastic IP to the Bastion host.
  3. Open Port 22 on the Bastion host to your office IP.
  4. Create a GPU instance in the private subnet without an Elastic IP.
  5. Open Port 22 on the GPU instance, allowing access only from the Bastion host's internal private IP.

To connect:

bash
# Connect to the Bastion host using SSH Agent Forwarding
ssh -A -i bastion.pem ubuntu@BASTION_EIP

# From within the Bastion, connect to the internal GPU node
ssh -i worker.pem ubuntu@GPU_PRIVATE_IP

3. Rate Limiting and WAF Integration

When using Route53, it is highly recommended to proxy your web traffic through a CDN and Web Application Firewall (WAF) like Cloudflare.

  1. In Cloudflare, add your domain.
  2. Configure your Route53 name servers to the ones provided by Cloudflare.
  3. In Cloudflare's DNS settings, create an A record pointing to your FOTOhub Elastic IP.
  4. Enable the "Proxy" status (orange cloud) in Cloudflare.
  5. In your FOTOhub Security Group, restrict Port 80 and 443 inbound traffic to only allow Cloudflare's published IP ranges.
bash
# Example: Adding a Cloudflare IP range to your Security Group
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "direction": "inbound",
    "protocol": "tcp",
    "port": 443,
    "cidr": "173.245.48.0/20",
    "description": "Cloudflare WAF Proxy"
  }'

By doing this, you ensure that malicious actors cannot bypass your WAF by connecting directly to your Elastic IP. All traffic is forced through Cloudflare's DDoS protection and rate limiting.

4. Continuous DNS Verification

If you are programmatically provisioning and destroying environments (e.g., in a CI/CD pipeline), you can use the DNS Verify endpoint to ensure your records have propagated before running integration tests.

python
import time
import requests

def wait_for_dns_propagation(zone_id, domain, timeout=600):
    start_time = time.time()
    while time.time() - start_time < timeout:
        res = requests.post(
            f"https://apis.fotohub.app/compute/v1/dns/zones/{zone_id}/verify",
            headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}
        )
        if res.json().get("status") == "verified":
            print(f"Domain {domain} successfully verified and propagated!")
            return True
        print("Waiting for DNS propagation...")
        time.sleep(30)
    raise TimeoutError("DNS propagation timed out.")

Advanced Networking Walkthroughs

1. Setting up a High-Availability Load Balancer with Auto-Scaling

When traffic to your LLM or ComfyUI instances spikes, you can distribute the load using a combination of Route53 weighted records and FOTOhub load balancers.

  1. Deploy multiple identical instances across different Availability Zones (e.g., eu-central-1a and eu-central-1b).
  2. Allocate Elastic IPs for each instance.
  3. Configure Route53 with weighted or latency-based routing policies pointing to the different EIPs.
python
import requests

# Deploy Instance 1 in AZ a
res1 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1a"}
)
inst1 = res1.json()["id"]

# Deploy Instance 2 in AZ b
res2 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1b"}
)
inst2 = res2.json()["id"]

# Allocate EIPs
eip1 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst1}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()
eip2 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst2}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()

print(f"Node 1 IP: {eip1['public_ip']}, Node 2 IP: {eip2['public_ip']}")

2. Implementing a Bastion Host (Jump Box)

For maximum security, avoid assigning Elastic IPs to your expensive GPU nodes. Instead, deploy a tiny CPU instance (e.g., t3.micro) as a Bastion host in a public subnet, and place your GPU instances in a private subnet.

  1. Create a t3.micro instance in the public subnet (eu-central-1a).
  2. Assign an Elastic IP to the Bastion host.
  3. Open Port 22 on the Bastion host to your office IP.
  4. Create a GPU instance in the private subnet without an Elastic IP.
  5. Open Port 22 on the GPU instance, allowing access only from the Bastion host's internal private IP.

To connect:

bash
# Connect to the Bastion host using SSH Agent Forwarding
ssh -A -i bastion.pem ubuntu@BASTION_EIP

# From within the Bastion, connect to the internal GPU node
ssh -i worker.pem ubuntu@GPU_PRIVATE_IP

3. Rate Limiting and WAF Integration

When using Route53, it is highly recommended to proxy your web traffic through a CDN and Web Application Firewall (WAF) like Cloudflare.

  1. In Cloudflare, add your domain.
  2. Configure your Route53 name servers to the ones provided by Cloudflare.
  3. In Cloudflare's DNS settings, create an A record pointing to your FOTOhub Elastic IP.
  4. Enable the "Proxy" status (orange cloud) in Cloudflare.
  5. In your FOTOhub Security Group, restrict Port 80 and 443 inbound traffic to only allow Cloudflare's published IP ranges.
bash
# Example: Adding a Cloudflare IP range to your Security Group
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "direction": "inbound",
    "protocol": "tcp",
    "port": 443,
    "cidr": "173.245.48.0/20",
    "description": "Cloudflare WAF Proxy"
  }'

By doing this, you ensure that malicious actors cannot bypass your WAF by connecting directly to your Elastic IP. All traffic is forced through Cloudflare's DDoS protection and rate limiting.

4. Continuous DNS Verification

If you are programmatically provisioning and destroying environments (e.g., in a CI/CD pipeline), you can use the DNS Verify endpoint to ensure your records have propagated before running integration tests.

python
import time
import requests

def wait_for_dns_propagation(zone_id, domain, timeout=600):
    start_time = time.time()
    while time.time() - start_time < timeout:
        res = requests.post(
            f"https://apis.fotohub.app/compute/v1/dns/zones/{zone_id}/verify",
            headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}
        )
        if res.json().get("status") == "verified":
            print(f"Domain {domain} successfully verified and propagated!")
            return True
        print("Waiting for DNS propagation...")
        time.sleep(30)
    raise TimeoutError("DNS propagation timed out.")

Advanced Networking Walkthroughs

1. Setting up a High-Availability Load Balancer with Auto-Scaling

When traffic to your LLM or ComfyUI instances spikes, you can distribute the load using a combination of Route53 weighted records and FOTOhub load balancers.

  1. Deploy multiple identical instances across different Availability Zones (e.g., eu-central-1a and eu-central-1b).
  2. Allocate Elastic IPs for each instance.
  3. Configure Route53 with weighted or latency-based routing policies pointing to the different EIPs.
python
import requests

# Deploy Instance 1 in AZ a
res1 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1a"}
)
inst1 = res1.json()["id"]

# Deploy Instance 2 in AZ b
res2 = requests.post(
    "https://apis.fotohub.app/compute/v1/instances",
    headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"},
    json={"catalog_id": "g5.xlarge", "subnet_id": "eu-central-1b"}
)
inst2 = res2.json()["id"]

# Allocate EIPs
eip1 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst1}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()
eip2 = requests.post(f"https://apis.fotohub.app/compute/v1/instances/{inst2}/elastic-ip", headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}).json()

print(f"Node 1 IP: {eip1['public_ip']}, Node 2 IP: {eip2['public_ip']}")

2. Implementing a Bastion Host (Jump Box)

For maximum security, avoid assigning Elastic IPs to your expensive GPU nodes. Instead, deploy a tiny CPU instance (e.g., t3.micro) as a Bastion host in a public subnet, and place your GPU instances in a private subnet.

  1. Create a t3.micro instance in the public subnet (eu-central-1a).
  2. Assign an Elastic IP to the Bastion host.
  3. Open Port 22 on the Bastion host to your office IP.
  4. Create a GPU instance in the private subnet without an Elastic IP.
  5. Open Port 22 on the GPU instance, allowing access only from the Bastion host's internal private IP.

To connect:

bash
# Connect to the Bastion host using SSH Agent Forwarding
ssh -A -i bastion.pem ubuntu@BASTION_EIP

# From within the Bastion, connect to the internal GPU node
ssh -i worker.pem ubuntu@GPU_PRIVATE_IP

3. Rate Limiting and WAF Integration

When using Route53, it is highly recommended to proxy your web traffic through a CDN and Web Application Firewall (WAF) like Cloudflare.

  1. In Cloudflare, add your domain.
  2. Configure your Route53 name servers to the ones provided by Cloudflare.
  3. In Cloudflare's DNS settings, create an A record pointing to your FOTOhub Elastic IP.
  4. Enable the "Proxy" status (orange cloud) in Cloudflare.
  5. In your FOTOhub Security Group, restrict Port 80 and 443 inbound traffic to only allow Cloudflare's published IP ranges.
bash
# Example: Adding a Cloudflare IP range to your Security Group
curl -X POST https://apis.fotohub.app/compute/v1/instances/inst_90f23b/security-rules \
  -H "Authorization: Bearer fh_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "direction": "inbound",
    "protocol": "tcp",
    "port": 443,
    "cidr": "173.245.48.0/20",
    "description": "Cloudflare WAF Proxy"
  }'

By doing this, you ensure that malicious actors cannot bypass your WAF by connecting directly to your Elastic IP. All traffic is forced through Cloudflare's DDoS protection and rate limiting.

4. Continuous DNS Verification

If you are programmatically provisioning and destroying environments (e.g., in a CI/CD pipeline), you can use the DNS Verify endpoint to ensure your records have propagated before running integration tests.

python
import time
import requests

def wait_for_dns_propagation(zone_id, domain, timeout=600):
    start_time = time.time()
    while time.time() - start_time < timeout:
        res = requests.post(
            f"https://apis.fotohub.app/compute/v1/dns/zones/{zone_id}/verify",
            headers={"Authorization": "Bearer fh_live_YOUR_API_KEY"}
        )
        if res.json().get("status") == "verified":
            print(f"Domain {domain} successfully verified and propagated!")
            return True
        print("Waiting for DNS propagation...")
        time.sleep(30)
    raise TimeoutError("DNS propagation timed out.")