Skip to content

Deploying iodine

Introduction

iodine is a DNS tunneling tool that enables IPv4 traffic to be tunneled through DNS queries and responses. This technique is useful when you’re on a restrictive network that blocks most traffic but allows DNS queries, such as some captive portals, corporate networks, or public WiFi hotspots.

The server component (iodined) runs on a machine with unrestricted internet access and a domain configured for DNS delegation. The client connects to this server by making DNS queries, effectively creating a virtual network interface that tunnels all traffic through DNS.

Key highlights of iodine:

  • DNS Tunneling: Tunnel IPv4 traffic through DNS queries and responses
  • Multiple Encodings: Supports various encoding schemes for different DNS configurations
  • Automatic Detection: Automatically detects the best encoding and fragment size
  • Raw Mode: Uses raw UDP when direct connection is possible for better performance
  • Multiple Users: Server supports multiple simultaneous client connections
  • Cross-Platform: Works on Linux, BSD, macOS, and Windows
  • Minimal Latency: Optimized for reasonable performance given DNS constraints
  • Lightweight: Small binary with minimal dependencies
  • Password Protection: Optional password authentication for server access
  • 100% Open Source: ISC licensed

This guide walks through deploying iodine server on Klutch.sh using Docker, configuring DNS delegation, and connecting clients.

Why Deploy iodine on Klutch.sh

Deploying iodine on Klutch.sh provides several advantages:

Always-On Server: Your DNS tunnel server runs 24/7, ready whenever you need to bypass restrictions.

Simplified Deployment: Klutch.sh handles the container deployment without manual server setup.

Persistent Configuration: Server settings survive restarts and redeployments.

Scalable Resources: Allocate resources based on expected tunnel traffic.

Environment Variable Management: Store tunnel passwords securely.

Prerequisites

Before deploying iodine on Klutch.sh, ensure you have:

  • A Klutch.sh account
  • A GitHub account with a repository for your configuration
  • A registered domain name with DNS control
  • Basic familiarity with Docker and DNS concepts
  • Understanding of network tunneling and its use cases

Understanding iodine Architecture

iodine creates a DNS tunnel through the following mechanism:

DNS Delegation: Your domain’s DNS is configured to delegate a subdomain to your iodine server.

Query Encoding: The client encodes data as DNS queries (typically TXT, NULL, or CNAME records).

Response Encoding: The server responds with encoded data in DNS response records.

Virtual Interface: Both client and server create TUN interfaces for routing traffic.

IP Assignment: The server assigns IP addresses to connected clients from a configured subnet.

Traffic Flow

Client App -> TUN Interface -> iodine client -> DNS Queries
-> DNS Server -> iodine server -> TUN Interface -> Internet

Preparing Your Repository

Create a GitHub repository for your iodine deployment.

Repository Structure

iodine-deploy/
├── Dockerfile
├── README.md
└── .dockerignore

Creating the Dockerfile

Create a Dockerfile in the root of your repository:

FROM alpine:latest
# Install iodine
RUN apk add --no-cache iodine
# Set environment variables
ENV TUNNEL_DOMAIN=${TUNNEL_DOMAIN}
ENV TUNNEL_PASSWORD=${TUNNEL_PASSWORD}
ENV TUNNEL_SUBNET=${TUNNEL_SUBNET:-10.0.0.1/24}
ENV TUNNEL_MTU=${TUNNEL_MTU:-1130}
# Create startup script
RUN echo '#!/bin/sh' > /start.sh && \
echo 'exec iodined -f -c -P "$TUNNEL_PASSWORD" -n "$TUNNEL_SUBNET" -m "$TUNNEL_MTU" "$TUNNEL_DOMAIN"' >> /start.sh && \
chmod +x /start.sh
# Expose DNS port
EXPOSE 53/udp
# Run iodined
CMD ["/start.sh"]

Advanced Dockerfile

For more control over the tunnel configuration:

FROM alpine:latest
# Install iodine and utilities
RUN apk add --no-cache iodine iptables
# Environment variables
ENV TUNNEL_DOMAIN=${TUNNEL_DOMAIN}
ENV TUNNEL_PASSWORD=${TUNNEL_PASSWORD}
ENV TUNNEL_SUBNET=${TUNNEL_SUBNET:-10.0.0.1/24}
ENV TUNNEL_MTU=${TUNNEL_MTU:-1130}
ENV TUNNEL_ENCODING=${TUNNEL_ENCODING:-}
ENV TUNNEL_LAZY_MODE=${TUNNEL_LAZY_MODE:-true}
ENV TUNNEL_FOREGROUND=true
# Create startup script with options
COPY <<'EOF' /start.sh
#!/bin/sh
ARGS="-f -c"
ARGS="$ARGS -P $TUNNEL_PASSWORD"
ARGS="$ARGS -n $TUNNEL_SUBNET"
ARGS="$ARGS -m $TUNNEL_MTU"
if [ -n "$TUNNEL_ENCODING" ]; then
ARGS="$ARGS -e $TUNNEL_ENCODING"
fi
if [ "$TUNNEL_LAZY_MODE" = "true" ]; then
ARGS="$ARGS -l"
fi
exec iodined $ARGS $TUNNEL_DOMAIN
EOF
RUN chmod +x /start.sh
# Expose DNS port
EXPOSE 53/udp
CMD ["/start.sh"]

Environment Variables Reference

VariableRequiredDefaultDescription
TUNNEL_DOMAINYes-The subdomain delegated to your server
TUNNEL_PASSWORDYes-Password for client authentication
TUNNEL_SUBNETNo10.0.0.1/24IP subnet for tunnel clients
TUNNEL_MTUNo1130MTU for the tunnel interface
TUNNEL_ENCODINGNoautoEncoding scheme (base32, base64, base128, etc.)
TUNNEL_LAZY_MODENotrueUse lazy mode for better performance

DNS Configuration

Before deploying, configure your domain’s DNS for iodine:

Required DNS Records

Add these records to your domain’s DNS:

TypeNameValue
NStunnelYour Klutch.sh hostname
AtunnelnsYour Klutch.sh IP address

Example for example.com:

tunnel.example.com. NS tunnelns.example.com.
tunnelns.example.com. A <your-klutch-ip>

The NS record delegates tunnel.example.com to the tunnelns.example.com nameserver, which points to your iodine server.

Deploying iodine on Klutch.sh

    Generate a Strong Password

    Create a secure password for your tunnel:

    Terminal window
    openssl rand -base64 24

    Configure DNS Records

    Set up the DNS delegation records as described above. Allow time for DNS propagation.

    Push Your Repository to GitHub

    Initialize and push your repository:

    Terminal window
    git init
    git add Dockerfile .dockerignore README.md
    git commit -m "Initial iodine deployment configuration"
    git remote add origin https://github.com/yourusername/iodine-deploy.git
    git push -u origin main

    Create a New Project on Klutch.sh

    Navigate to the Klutch.sh dashboard and create a new project named “iodine” or “dns-tunnel”.

    Create a New App

    Within your project, create a new app. Connect your GitHub account and select the repository containing your Dockerfile.

    Configure Traffic

    Note: iodine uses UDP port 53 for DNS traffic. Configure your deployment for UDP access if supported.

    Set Environment Variables

    Add the following environment variables:

    VariableValue
    TUNNEL_DOMAINtunnel.yourdomain.com
    TUNNEL_PASSWORDYour generated password
    TUNNEL_SUBNET10.0.0.1/24

    Deploy Your Application

    Click Deploy to start the build process.

    Verify DNS Configuration

    Test DNS resolution to your tunnel domain:

    Terminal window
    dig NS tunnel.yourdomain.com

Connecting Clients

Installing the Client

Install iodine on your client machine:

Linux/macOS:

Terminal window
# Debian/Ubuntu
sudo apt install iodine
# macOS with Homebrew
brew install iodine
# Alpine
apk add iodine

Windows: Download from the official website.

Connecting to the Tunnel

Connect to your iodine server:

Terminal window
sudo iodine -f -P your_password tunnel.yourdomain.com

If successful, you’ll see:

Opened dns0
Opened IPv4 UDP socket
Connection setup complete, transmitting data.

Routing Traffic

Route traffic through the tunnel:

Terminal window
# Add route for specific destination
sudo ip route add 10.0.0.0/8 via 10.0.0.1 dev dns0
# Or set as default gateway (replaces current route)
sudo ip route replace default via 10.0.0.1 dev dns0

Performance Considerations

DNS tunneling has inherent limitations:

  • Bandwidth: Expect 1-50 KB/s depending on network conditions
  • Latency: Higher latency than direct connections due to encoding overhead
  • Reliability: Some DNS servers may cache or modify responses

Optimization Tips

  • Use NULL record type when possible (best encoding efficiency)
  • Enable lazy mode for better performance on stable connections
  • Adjust MTU if experiencing fragmentation
  • Use a DNS server that doesn’t rewrite responses

Security Considerations

  • Use Strong Passwords: Prevent unauthorized tunnel access
  • Monitor Usage: Check for suspicious tunnel traffic
  • Understand Risks: DNS tunneling may violate network policies
  • Legal Compliance: Ensure you have permission to bypass network restrictions

Troubleshooting

Connection Fails

  • Verify DNS delegation is configured correctly
  • Check that UDP port 53 is accessible
  • Test with dig TXT test.tunnel.yourdomain.com

Poor Performance

  • Try different encoding schemes with -e flag
  • Adjust MTU with -m flag
  • Test from different networks

Tunnel Unstable

  • Enable lazy mode with -l flag
  • Check for DNS caching issues
  • Verify server is running with iodine -D

Additional Resources

Conclusion

Deploying iodine on Klutch.sh gives you an always-available DNS tunnel server for bypassing network restrictions. While DNS tunneling has performance limitations, it provides a reliable escape route when other protocols are blocked.

Use this tool responsibly and ensure compliance with applicable network policies and regulations.