Building an AI Agent That Manages Custom Domains on Deployxa | Deployxa

Managing custom domains (DNS, SSL, routing) is tedious. Here is how to build an AI agent that manages custom domains automatically via Deployxa MCP.

← Back to Dispatch Articles
Engineering Log

Building an AI Agent That Manages Custom Domains on Deployxa

Managing custom domains (DNS, SSL, routing) is tedious. Here is how to build an AI agent that manages custom domains automatically via Deployxa MCP.

Building an AI Agent That Manages Custom Domains on Deployxa

Managing custom domains is tedious: you need to add the domain to the platform, configure DNS records, wait for DNS propagation, provision an SSL certificate, verify the routing, and troubleshoot issues. For teams with many apps and many domains, this is a significant operational burden. What you need is an AI agent that manages custom domains automatically: adds domains, configures DNS, provisions SSL, and verifies routing. With the Deployxa MCP server, this is straightforward to build. Here is how.

The direct answer is that a custom domain management agent is a script that uses the Deployxa MCP server to add custom domains (via deployxa_add_domain), check SSL status (via deployxa_get_ssl_status), verify routing (via deployxa_doctor), and troubleshoot issues. The agent uses an LLM to interpret natural language commands (e.g., "add myapp.com to my-app") and to execute them via the MCP server. For more on custom domains, see our article on how we handle SSL at scale.

Why Manual Domain Management Is Tedious

Three problems make manual domain management tedious. First, it is multi-step. Adding a custom domain involves multiple steps (add domain, configure DNS, wait for propagation, provision SSL, verify routing), each of which takes time. Second, it is error-prone. Misconfiguring DNS records, typos in domain names, or incorrect SSL configuration can cause issues that are hard to debug. Third, it does not scale. For teams with many apps and many domains, the operational burden grows linearly, which means it becomes a significant time sink. An AI agent solves all three problems: it automates the multi-step process, it eliminates human error, and it scales to any number of domains. For more on agentic patterns, see our article on building a custom AI deployment assistant.

What the Domain Management Agent Does

The custom domain management agent performs the following tasks:

  1. Add a custom domain. The agent calls deployxa_add_domain to add a custom domain to an app.
  1. Provide DNS instructions. The agent provides the DNS records that need to be configured (e.g., CNAME to cname.deployxa.app), and waits for the user to configure them.
  1. Check DNS propagation. The agent periodically checks whether the DNS has propagated (by resolving the domain and checking if it points to Deployxa).
  1. Check SSL status. The agent calls deployxa_get_ssl_status to check whether the SSL certificate has been provisioned.
  1. Verify routing. The agent calls deployxa_doctor to verify that the domain is routing correctly and that the app is healthy.
  1. Troubleshoot issues. If any step fails (e.g., DNS not propagated, SSL not provisioned, routing not working), the agent uses an LLM to diagnose the issue and recommend a fix.

Step-by-Step: Building the Domain Management Agent

Here is how to build the custom domain management agent in Python, using the Deployxa MCP server and an LLM.

Step 1: Install dependencies

pip install openai requests dnspython
npm install -g @deployxa/mcp-server
deployxa-mcp login

Step 2: Create the agent script

# domain_agent.py
import openai
import requests
import dns.resolver
import time
import json
from datetime import datetime

# Configuration
DEPLOYXA_MCP_URL = "http://localhost:3000/mcp"
SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/..."
DEPLOYXA_CNAME_TARGET = "cname.deployxa.app"

def call_deployxa(tool, params):
    response = requests.post(DEPLOYXA_MCP_URL, json={"tool": tool, "params": params})
    return response.json()

def send_slack_notification(message, is_alert=False):
    emoji = "🌐" if not is_alert else "🚨"
    requests.post(SLACK_WEBHOOK_URL, json={"text": f"{emoji} {message}"})

def check_dns_propagation(domain):
    """Check if the domain's DNS points to Deployxa."""
    try:
        answers = dns.resolver.resolve(domain, 'CNAME')
        for answer in answers:
            if DEPLOYXA_CNAME_TARGET in str(answer):
                return True
        return False
    except dns.resolver.NXDOMAIN:
        return False
    except dns.resolver.NoAnswer:
        # Try A record
        try:
            answers = dns.resolver.resolve(domain, 'A')
            # Check if any A record points to Deployxa's IP
            # (In a real implementation, you would check against known Deployxa IPs)
            return len(answers) > 0
        except:
            return False
    except Exception:
        return False

def add_custom_domain(app_id, domain):
    """Add a custom domain to an app."""
    print(f"Adding domain {domain} to app {app_id}...")
    
    result = call_deployxa("deployxa_add_domain", {
        "app_id": app_id,
        "domain": domain,
    })
    
    if result.get("status") == "success":
        print(f"  Domain added. Configure DNS:")
        print(f"    CNAME {domain} -> {DEPLOYXA_CNAME_TARGET}")
        send_slack_notification(
            f"Domain {domain} added to app {app_id}.\n"
            f"Please configure DNS: CNAME {domain} -> {DEPLOYXA_CNAME_TARGET}"
        )
        return True
    else:
        print(f"  Failed: {result.get('error')}")
        send_slack_notification(f"Failed to add domain {domain}: {result.get('error')}", is_alert=True)
        return False

def wait_for_dns(domain, timeout_minutes=60):
    """Wait for DNS to propagate."""
    print(f"Waiting for DNS propagation for {domain}...")
    
    start = time.time()
    while time.time() - start < timeout_minutes * 60:
        if check_dns_propagation(domain):
            print(f"  DNS propagated")
            return True
        print(f"  DNS not yet propagated, waiting 60 seconds...")
        time.sleep(60)
    
    print(f"  DNS did not propagate within {timeout_minutes} minutes")
    send_slack_notification(f"DNS for {domain} did not propagate within {timeout_minutes} minutes", is_alert=True)
    return False

def check_ssl_status(app_id, domain):
    """Check if SSL is provisioned."""
    result = call_deployxa("deployxa_get_ssl_status", {
        "app_id": app_id,
        "domain": domain,
    })
    
    ssl_status = result.get("ssl_status", "unknown")
    return ssl_status == "active"

def wait_for_ssl(app_id, domain, timeout_minutes=10):
    """Wait for SSL to be provisioned."""
    print(f"Waiting for SSL provisioning for {domain}...")
    
    start = time.time()
    while time.time() - start < timeout_minutes * 60:
        if check_ssl_status(app_id, domain):
            print(f"  SSL provisioned")
            return True
        print(f"  SSL not yet provisioned, waiting 60 seconds...")
        time.sleep(60)
    
    print(f"  SSL was not provisioned within {timeout_minutes} minutes")
    send_slack_notification(f"SSL for {domain} was not provisioned within {timeout_minutes} minutes", is_alert=True)
    return False

def verify_routing(app_id, domain):
    """Verify that the domain is routing correctly."""
    result = call_deployxa("deployxa_doctor", {"app_id": app_id})
    
    # Check if the DNS check passed
    for check in result.get("checks", []):
        if check.get("name") == "DNS resolution" and domain in check.get("detail", ""):
            return check.get("status") == "pass"
    
    return result.get("grade") in ["A", "B"]

def setup_custom_domain(app_id, domain):
    """Set up a custom domain end-to-end."""
    print(f"\n{'='*60}")
    print(f"Setting up custom domain: {domain}")
    print(f"{'='*60}")
    
    # Step 1: Add the domain
    if not add_custom_domain(app_id, domain):
        return False
    
    # Step 2: Wait for DNS propagation
    if not wait_for_dns(domain):
        return False
    
    # Step 3: Wait for SSL provisioning
    if not wait_for_ssl(app_id, domain):
        return False
    
    # Step 4: Verify routing
    if verify_routing(app_id, domain):
        print(f"\nāœ… Custom domain {domain} is live!")
        send_slack_notification(
            f"āœ… Custom domain {domain} is live!\n"
            f"  SSL: Active\n"
            f"  Routing: Verified\n"
            f"  URL: https://{domain}"
        )
        return True
    else:
        print(f"\nāŒ Routing verification failed for {domain}")
        send_slack_notification(f"Routing verification failed for {domain}", is_alert=True)
        return False

def troubleshoot_domain(app_id, domain):
    """Troubleshoot domain issues using an LLM."""
    client = openai.OpenAI()
    
    # Gather diagnostic information
    ssl_result = call_deployxa("deployxa_get_ssl_status", {"app_id": app_id, "domain": domain})
    doctor_result = call_deployxa("deployxa_doctor", {"app_id": app_id})
    dns_propagated = check_dns_propagation(domain)
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": "You are a domain troubleshooting agent. Diagnose the domain issue and recommend a fix."
            },
            {
                "role": "user",
                "content": f"""Domain: {domain}
DNS propagated: {dns_propagated}
SSL status: {ssl_result.get('ssl_status', 'unknown')}
Doctor grade: {doctor_result.get('grade', 'unknown')}
Doctor checks: {json.dumps(doctor_result.get('checks', []), indent=2)}

Diagnose the issue and recommend a fix.
"""
            }
        ]
    )
    
    diagnosis = response.choices[0].message.content
    print(f"\nDiagnosis: {diagnosis}")
    send_slack_notification(f"Domain {domain} troubleshooting:\n{diagnosis}")

if __name__ == "__main__":
    # Example: set up a custom domain
    APP_ID = "123"
    DOMAIN = "myapp.com"
    
    success = setup_custom_domain(APP_ID, DOMAIN)
    
    if not success:
        print("\nSetup failed, troubleshooting...")
        troubleshoot_domain(APP_ID, DOMAIN)

Step 3: Run the agent

python domain_agent.py

The agent adds the custom domain, waits for DNS propagation, waits for SSL provisioning, verifies routing, and reports the result via Slack. If any step fails, it troubleshoots the issue using an LLM.

Step 4: Deploy the agent

The agent can be run on-demand (when you need to add a domain) or deployed as a Deployxa app for continuous domain management.

Common Pitfalls and Troubleshooting

The first pitfall is DNS propagation delays. DNS propagation can take anywhere from a few minutes to 48 hours, which means the agent needs to be patient. The fix is to set a long timeout (e.g., 60 minutes) and to check periodically. The second pitfall is DNS misconfiguration. The user might configure the DNS records incorrectly (e.g., wrong CNAME target, wrong record type), which prevents propagation. The fix is to provide clear DNS instructions and to verify the DNS configuration. The third pitfall is SSL provisioning failures. SSL provisioning can fail for various reasons (e.g., Let's Encrypt rate limits, domain validation failures), which means the agent needs to handle failures gracefully. The fix is to retry SSL provisioning and to troubleshoot if retries fail. The fourth pitfall is apex domain issues. Apex domains (e.g., myapp.com) cannot use CNAME records (in standard DNS), which means they need an A record or an ALIAS record. The fix is to provide different instructions for apex domains (A record) and subdomains (CNAME record). The fifth pitfall is wildcard domains. Wildcard domains (e.g., *.myapp.com) require a different SSL certificate (a wildcard certificate), which might need additional configuration. The fix is to handle wildcard domains specially in the agent.

Conclusion: Let the Agent Manage Your Domains

Manual domain management is tedious, error-prone, and does not scale. An AI agent that manages custom domains automatically is the sustainable solution. With the Deployxa MCP server and an LLM, you can build a domain management agent that adds domains, configures DNS, provisions SSL, and verifies routing, all automatically. Stop managing domains manually and start automating.

Ready to build your domain management agent? Install the Deployxa MCP server with npm i -g @deployxa/mcp-server, run deployxa-mcp login, and start building. For more on agentic workflows, see our articles on the agentic log analysis pipeline and building an AI agent that optimizes your database. Learn about the agentic database backup pipeline and building an AI agent that manages your secrets in our companion articles. Explore our free developer tools to speed up your workflow.

Ready to deploy with Deployxa?

Deploy your apps globally with automatic SSL and AI diagnostics.

Start Free Now