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 -> InternetPreparing Your Repository
Create a GitHub repository for your iodine deployment.
Repository Structure
iodine-deploy/├── Dockerfile├── README.md└── .dockerignoreCreating the Dockerfile
Create a Dockerfile in the root of your repository:
FROM alpine:latest
# Install iodineRUN apk add --no-cache iodine
# Set environment variablesENV 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 scriptRUN 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 portEXPOSE 53/udp
# Run iodinedCMD ["/start.sh"]Advanced Dockerfile
For more control over the tunnel configuration:
FROM alpine:latest
# Install iodine and utilitiesRUN apk add --no-cache iodine iptables
# Environment variablesENV 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 optionsCOPY <<'EOF' /start.sh#!/bin/shARGS="-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_DOMAINEOF
RUN chmod +x /start.sh
# Expose DNS portEXPOSE 53/udp
CMD ["/start.sh"]Environment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
TUNNEL_DOMAIN | Yes | - | The subdomain delegated to your server |
TUNNEL_PASSWORD | Yes | - | Password for client authentication |
TUNNEL_SUBNET | No | 10.0.0.1/24 | IP subnet for tunnel clients |
TUNNEL_MTU | No | 1130 | MTU for the tunnel interface |
TUNNEL_ENCODING | No | auto | Encoding scheme (base32, base64, base128, etc.) |
TUNNEL_LAZY_MODE | No | true | Use 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:
| Type | Name | Value |
|---|---|---|
| NS | tunnel | Your Klutch.sh hostname |
| A | tunnelns | Your 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:
openssl rand -base64 24Configure 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:
git initgit add Dockerfile .dockerignore README.mdgit commit -m "Initial iodine deployment configuration"git remote add origin https://github.com/yourusername/iodine-deploy.gitgit push -u origin mainCreate 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:
| Variable | Value |
|---|---|
TUNNEL_DOMAIN | tunnel.yourdomain.com |
TUNNEL_PASSWORD | Your generated password |
TUNNEL_SUBNET | 10.0.0.1/24 |
Deploy Your Application
Click Deploy to start the build process.
Verify DNS Configuration
Test DNS resolution to your tunnel domain:
dig NS tunnel.yourdomain.comConnecting Clients
Installing the Client
Install iodine on your client machine:
Linux/macOS:
# Debian/Ubuntusudo apt install iodine
# macOS with Homebrewbrew install iodine
# Alpineapk add iodineWindows: Download from the official website.
Connecting to the Tunnel
Connect to your iodine server:
sudo iodine -f -P your_password tunnel.yourdomain.comIf successful, you’ll see:
Opened dns0Opened IPv4 UDP socketConnection setup complete, transmitting data.Routing Traffic
Route traffic through the tunnel:
# Add route for specific destinationsudo 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 dns0Performance 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
-eflag - Adjust MTU with
-mflag - Test from different networks
Tunnel Unstable
- Enable lazy mode with
-lflag - Check for DNS caching issues
- Verify server is running with
iodine -D
Additional Resources
- iodine Official Website
- iodine GitHub Repository
- Arch Linux iodine Wiki
- Klutch.sh Persistent Volumes
- Klutch.sh Deployments
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.