Metadata-Version: 2.4
Name: suxitunnel
Version: 0.1.2
Summary: A simple Python library to expose local servers using Cloudflare Tunnel
Project-URL: Homepage, https://github.com/sadwx/suxitunnel
Project-URL: Repository, https://github.com/sadwx/suxitunnel
Project-URL: Issues, https://github.com/sadwx/suxitunnel/issues
Project-URL: Documentation, https://github.com/sadwx/suxitunnel#readme
Author-email: Simon <simon@suxi.world>
License-Expression: MIT
License-File: LICENSE
Keywords: cloudflare,development,expose,localhost,tunnel
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.14
Requires-Dist: requests>=2.32.0
Description-Content-Type: text/markdown

# suxitunnel

A simple Python library to expose your local server to the internet using Cloudflare's infrastructure.

Inspired by [localtunnel-py](https://github.com/gweidart/localtunnel-py) but using Cloudflare's global network for better performance and DDoS protection.

## Installation

```bash
pip install suxitunnel
```

## Quick Start

```python
from suxitunnel import Tunnel

# Expose local port 8000
tunnel = Tunnel(8000)
print(f"Your URL: {tunnel.url}")

# Keep your app running...
input("Press Enter to close tunnel...")

tunnel.close()
```

That's it! No configuration, no authentication, no manual setup.

## Features

- 🚀 **Zero Configuration** - Just pass a port number
- 🔒 **Secure** - Uses Cloudflare's infrastructure with DDoS protection
- 🌍 **Global CDN** - Fast access from anywhere in the world
- 📦 **Auto-install** - Automatically downloads cloudflared if needed
- 🐍 **Simple API** - Clean, Pythonic interface

## Usage

### Basic Usage

```python
from suxitunnel import Tunnel

tunnel = Tunnel(8000)
print(tunnel.url)  # https://random-name.trycloudflare.com

# Your local server is now public!
# Keep tunnel alive...
tunnel.close()  # Close when done
```

### Context Manager (Recommended)

```python
from suxitunnel import Tunnel

with Tunnel(8000) as tunnel:
    print(f"Public URL: {tunnel.url}")
    # Do your work...
    # Tunnel automatically closes when exiting the block
```

### With Flask

```python
from flask import Flask
from suxitunnel import Tunnel
import threading

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello from Flask!"

if __name__ == '__main__':
    # Start tunnel in background
    tunnel = Tunnel(5000)
    print(f"🌐 Public URL: {tunnel.url}")
    
    # Start Flask
    app.run(port=5000)
```

### With FastAPI

```python
from fastapi import FastAPI
from suxitunnel import Tunnel
import uvicorn

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello from FastAPI!"}

if __name__ == "__main__":
    # Start tunnel
    tunnel = Tunnel(8000)
    print(f"🌐 Public URL: {tunnel.url}")
    
    # Start FastAPI
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### Check Tunnel Status

```python
tunnel = Tunnel(8000)

print(tunnel.url)           # Public URL
print(tunnel.is_alive())    # True if tunnel is running
print(tunnel.port)          # 8000
print(tunnel)               # <Tunnel port=8000 url=https://... status=active>
```

### Custom Host

```python
# Tunnel a service running on a different host
tunnel = Tunnel(8000, host="192.168.1.100")
```

### Manual cloudflared Path

```python
# Use specific cloudflared binary
tunnel = Tunnel(8000, cloudflared_path="/usr/local/bin/cloudflared")
```

### Disable Auto-download

```python
# Don't automatically download cloudflared
tunnel = Tunnel(8000, auto_download=False)
```

## API Reference

### `Tunnel(port, host="localhost", cloudflared_path=None, auto_download=True)`

Create a tunnel to expose a local port.

**Parameters:**
- `port` (int): Local port to expose (required)
- `host` (str): Local hostname (default: "localhost")
- `cloudflared_path` (str): Path to cloudflared binary (auto-detected if None)
- `auto_download` (bool): Auto-download cloudflared if not found (default: True)

**Attributes:**
- `url` (str): Public HTTPS URL for the tunnel
- `port` (int): Local port being exposed
- `host` (str): Local hostname
- `is_alive()` (bool): Check if tunnel is running
- `close()`: Close the tunnel

**Example:**
```python
tunnel = Tunnel(8000)
print(tunnel.url)  # https://abc123.trycloudflare.com
tunnel.close()
```

### `open_tunnel(port, host="localhost")`

Convenience function to create a tunnel.

```python
from suxitunnel import open_tunnel

tunnel = open_tunnel(8000)
```

## How It Works

### Technical Overview

This library uses **Cloudflare Quick Tunnels** (also called TryCloudflare), which:

1. Creates an outbound HTTP/2 connection from your machine to Cloudflare's edge
2. No inbound ports are opened on your machine (firewall-friendly!)
3. No authentication or account required
4. Traffic is routed through Cloudflare's global network
5. Automatic HTTPS with valid certificate

**Architecture:**
```
Your App (localhost:8000) → cloudflared → Cloudflare Edge → Internet
                             (HTTP/2)     (Global CDN)     (HTTPS)
```

### Cloudflared Binary

The library automatically downloads the `cloudflared` binary on first use if it's not already installed. The binary is saved to the library's installation directory.

Supported platforms:
- Linux (x64, ARM64)
- macOS (x64, ARM64/M1)
- Windows (x64)

## Comparison with Alternatives

| Feature | suxitunnel | localtunnel | ngrok |
|---------|------------------|-------------|-------|
| Free tier | ✅ Unlimited | ✅ Yes | ⚠️ Limited |
| Custom domains | ❌ Random | ❌ Random | 💰 Paid |
| DDoS protection | ✅ Included | ❌ No | ⚠️ Limited |
| Global CDN | ✅ Yes | ❌ No | ⚠️ Limited |
| Auth required | ✅ No | ✅ No | ⚠️ Yes |
| Connection limits | ✅ None | ⚠️ Yes | ⚠️ Yes |
| Rate limits | ✅ Generous | ⚠️ Yes | ⚠️ Yes |

## Limitations

1. **Random URLs**: Each tunnel gets a random `*.trycloudflare.com` URL (no custom domains)
2. **Temporary**: Tunnels are meant for development/testing, not production
3. **No persistence**: URL changes each time you create a new tunnel
4. **Rate limits**: Subject to Cloudflare's fair use policy

For production use with custom domains, see the full [cloudflared documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/).

## Security Considerations

### What This Tunnel Provides

✅ **DDoS protection** - Cloudflare's network absorbs attacks  
✅ **HTTPS encryption** - Valid SSL certificate included  
✅ **No exposed ports** - Outbound connection only  
✅ **Firewall-friendly** - Works behind NAT/firewalls  

### What You Still Need

⚠️ **Application security** - Implement authentication/authorization  
⚠️ **Input validation** - Protect against malicious input  
⚠️ **Rate limiting** - Prevent abuse of your endpoints  
⚠️ **Access control** - Not everyone should access your tunnel  

**Important:** Once your local server is exposed via a tunnel, anyone with the URL can access it. Make sure your application has proper authentication!

### Best Practices

```python
# ❌ DON'T: Expose services without authentication
tunnel = Tunnel(8000)  # If port 8000 has no auth, anyone can access it!

# ✅ DO: Use authentication in your application
from flask import Flask, request, abort
from functools import wraps

def require_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.headers.get('Authorization')
        if auth != 'Bearer YOUR_SECRET_TOKEN':
            abort(401)
        return f(*args, **kwargs)
    return decorated

@app.route('/api/data')
@require_auth  # Protected!
def get_data():
    return {"data": "sensitive"}
```

## Troubleshooting

### "cloudflared not found"

The library should auto-download cloudflared. If it fails:

```bash
# Manual install
# macOS
brew install cloudflare/cloudflare/cloudflared

# Linux
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared

# Or disable auto-download and specify path
tunnel = Tunnel(8000, cloudflared_path="/path/to/cloudflared", auto_download=False)
```

### "Tunnel failed to start"

Check that:
1. Your local service is running: `curl http://localhost:8000`
2. The port is not already in use
3. You have internet connectivity
4. Firewall allows outbound HTTPS (port 443)

### Tunnel URL not appearing

The library waits up to 30 seconds for the URL. If it times out:
1. Check your internet connection
2. Verify cloudflared is working: `cloudflared --version`
3. Try running manually: `cloudflared tunnel --url http://localhost:8000`

### Random disconnections

Quick Tunnels are designed for temporary use. For stable connections:
1. Restart the tunnel when disconnected
2. For production, use authenticated Cloudflare Tunnels with named tunnels
3. Implement automatic reconnection logic

## Examples

See the `examples/` directory for complete working examples:

- `basic_example.py` - Simplest usage
- `flask_example.py` - Flask integration
- `fastapi_example.py` - FastAPI integration
- `context_manager.py` - Using with context manager
- `multiple_tunnels.py` - Running multiple tunnels

## Development

```bash
# Clone the repo
git clone https://github.com/sadwx/suxitunnel.git
cd suxitunnel

# Install in development mode
pip install -e .

# Run tests
python -m pytest tests/
```

## License

MIT License - see LICENSE file for details.

## Related Projects

- [cloudflared](https://github.com/cloudflare/cloudflared) - Official Cloudflare Tunnel client
- [localtunnel-py](https://github.com/gweidart/localtunnel-py) - Similar library using localtunnel
- [pyngrok](https://github.com/alexdlaird/pyngrok) - Python wrapper for ngrok

## Credits

This library is a Python wrapper around [cloudflared](https://github.com/cloudflare/cloudflared), the official Cloudflare Tunnel client.

Inspired by the simplicity of [localtunnel-py](https://github.com/gweidart/localtunnel-py).
