Duration 2.5 hours
Day 1 of 2

Learning Objectives

By the end of this module, students will be able to:

  • Set up ngrok for local development
  • Configure static domains for consistent URLs
  • Implement basic authentication
  • Connect a SignalWire phone number to their agent
  • Make their first live call

Topics

1. The Exposure Problem (15 min)

Why Tunneling?

Your agent runs on localhost:3000, but SignalWire needs to reach it from the internet.

┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│  SignalWire │ ──X──>  │  Firewall   │ ──X──>  │ Your Agent  │
│   Cloud     │         │  NAT/Router │         │ localhost   │
└─────────────┘         └─────────────┘         └─────────────┘
                              ▲
                              │
                    Cannot reach directly!

Solutions

Solution Use Case Complexity
ngrok Development Low
Cloudflare Tunnel Development/Production Medium
Cloud deployment Production High
Port forwarding Not recommended High risk

2. ngrok Setup (30 min)

Installation Verification

ngrok version
# ngrok version 3.x.x

Basic Tunnel

# Start your agent first
python agent.py

# In another terminal
ngrok http 3000

ngrok Output

Session Status                online
Account                       your@email.com (Plan: Free)
Version                       3.x.x
Region                        United States (us)
Latency                       45ms
Web Interface                 http://127.0.0.1:4040
Forwarding                    https://a1b2c3d4.ngrok.io -> http://localhost:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

Key Information

Field Meaning
Forwarding URL Public URL for your agent
Web Interface Local dashboard for inspection
Latency Round-trip time to ngrok

Testing the Tunnel

# From another terminal or browser
curl https://a1b2c3d4.ngrok.io

3. Static Domains (20 min)

The Problem with Random URLs

Each ngrok restart creates a new URL:

  • https://a1b2c3d4.ngrok.io (Monday)
  • https://e5f6g7h8.ngrok.io (Tuesday)

You must update SignalWire each time!

Static Domain Solution

ngrok free accounts get one static domain:

# Set up static domain (one-time)
ngrok http --url=https://your-name.ngrok-free.app 3000

Now the URL never changes!


4. Basic Authentication (25 min)

Why Authentication?

Without auth, anyone who discovers your URL can:

  • Trigger your agent
  • Rack up API costs
  • Access function endpoints

How the SDK Handles Authentication

The SDK automatically secures your agent with HTTP Basic Authentication. When you start your agent, you’ll see the credentials printed:

Agent 'my-agent' is available at:
URL: http://localhost:3000
Basic Auth: signalwire:7vVZ8iMTOWL0Y7-BG6xaN3qhjmcm4Sf59nORNdlF9bs (source: generated)

Important: The password is randomly generated and changes every restart unless you set environment variables.

Setting Persistent Credentials

To keep the same credentials across restarts, set these environment variables. You have two options:

Option 1: Export directly (temporary, current terminal only)

export SWML_BASIC_AUTH_USER=signalwire
export SWML_BASIC_AUTH_PASSWORD=your-secure-password-here
python agent.py

Option 2: Use a .env file with python-dotenv (recommended)

First, install python-dotenv:

pip install python-dotenv

Create a .env file:

# .env
SWML_BASIC_AUTH_USER=signalwire
SWML_BASIC_AUTH_PASSWORD=your-secure-password-here

Then load it in your agent:

from dotenv import load_dotenv
load_dotenv()  # Load .env before creating agent

from signalwire_agents import AgentBase
agent = AgentBase(name="my-agent")
# ... rest of agent

Now when you start your agent, you’ll see:

Agent 'my-agent' is available at:
URL: http://localhost:3000
Basic Auth: signalwire:your-secure-password-here (source: environment)

Notice the source changed from generated to environment.

URL Format with Auth

https://username:password@your-name.ngrok-free.app/agent

Testing Auth

# Without auth - should fail
curl https://your-name.ngrok-free.app/agent
# 401 Unauthorized

# With auth - should work (use credentials from agent startup output)
curl https://signalwire:your-secure-password-here@your-name.ngrok-free.app/agent
# Returns SWML

5. SignalWire Configuration (30 min)

Step 1: Access Your Space

  1. Log in to SignalWire dashboard
  2. Select your project
  3. Navigate to Phone Numbers

Step 2: Purchase a Number (if needed)

  1. Click “Buy a Number”
  2. Select area code
  3. Choose number type (local recommended for testing)
  4. Complete purchase

Step 3: Configure Voice URL

  1. Click on your phone number
  2. Find “Voice and Fax Settings”
  3. Set “When a call comes in”:
    • Handle calls using: SWML Script
    • URL: https://user:pass@your-name.ngrok-free.app/agent

Step 4: Save and Test

  1. Click Save
  2. Call your SignalWire number
  3. Hear your agent respond!

Configuration Screenshot Guide

┌─────────────────────────────────────────────────────────────────┐
│ Phone Number: +1 (555) 123-4567                                 │
├─────────────────────────────────────────────────────────────────┤
│ Voice and Fax Settings                                          │
│                                                                 │
│ When a call comes in:                                           │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Handle calls using: [SWML Script          ▼]                │ │
│ └─────────────────────────────────────────────────────────────┘ │
│                                                                 │
│ URL:                                                            │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ https://user:pass@your-name.ngrok-free.app/agent            │ │
│ └─────────────────────────────────────────────────────────────┘ │
│                                                                 │
│ HTTP Method: [POST ▼]                                           │
│                                                                 │
│ [Save Changes]                                                  │
└─────────────────────────────────────────────────────────────────┘

6. Troubleshooting Connections (20 min)

Common Issues

ngrok Not Running

Symptom: SignalWire shows connection errors Fix: Ensure ngrok is running in a terminal

Wrong Port

Symptom: ngrok shows 502 Bad Gateway Fix: Match ngrok port to agent port

# Agent runs on 5000
python agent.py  # PORT=5000

# ngrok must match
ngrok http 5000
Auth Mismatch

Symptom: 401 Unauthorized Fix: Ensure credentials match between agent and SignalWire URL

Agent Crashed

Symptom: 502/503 errors Fix: Check agent terminal for errors, restart

Debugging with ngrok Inspector

Open http://127.0.0.1:4040 to see:

  • All requests to your tunnel
  • Request/response bodies
  • Timing information

Test Checklist

# 1. Agent running?
curl http://localhost:3000/agent

# 2. ngrok tunnel working?
curl https://your-name.ngrok-free.app/agent

# 3. Auth working?
curl https://user:pass@your-name.ngrok-free.app/agent

# 4. SWML valid?
swaig-test agent.py --dump-swml

Complete Setup Example

agent.py

#!/usr/bin/env python3
from dotenv import load_dotenv
load_dotenv()  # Load .env file

from signalwire_agents import AgentBase

agent = AgentBase(
    name="my-first-agent",
    route="/agent"
)

# Configuration
agent.prompt_add_section(
    "Role",
    "You are a friendly assistant. Greet callers warmly and "
    "ask how you can help them today."
)

agent.add_language("English", "en-US", "rime.spore")

if __name__ == "__main__":
    agent.run()

.env

# Authentication credentials (SDK reads these automatically)
SWML_BASIC_AUTH_USER=signalwire
SWML_BASIC_AUTH_PASSWORD=my-secure-password-123

Start Commands

# Terminal 1: Start agent
source .venv/bin/activate
pip install python-dotenv  # If not already installed
python agent.py

# You'll see output like:
# Agent 'my-first-agent' is available at:
# URL: http://localhost:3000
# Basic Auth: signalwire:my-secure-password-123 (source: environment)

# Terminal 2: Start tunnel
ngrok http --url=https://my-agent.ngrok-free.app 3000

SignalWire URL

Use the credentials shown in your agent’s startup output:

https://signalwire:my-secure-password-123@my-agent.ngrok-free.app/agent

Key Takeaways

  1. ngrok bridges local to internet - Essential for development
  2. Static domains save time - Same URL across restarts
  3. Always use authentication - Protect your endpoints
  4. Test the chain - Agent → ngrok → SignalWire
  5. Use ngrok inspector - Debug connection issues

Preparation for Lab 1.4

  • Agent working locally (from Lab 1.2)
  • ngrok installed and authenticated
  • SignalWire account with phone number
  • Phone to make test call

Lab Preview

In Lab 1.4, you will:

  1. Set up ngrok with static domain
  2. Add authentication to your agent
  3. Configure SignalWire phone number
  4. Make your first live call!

Back to top

SignalWire AI Agents Certification Program