unsandbox.com

Anonymous remote code, compile, & execution API for humans & machine learning agents.

Docs 📚 View Pricing →
unsandbox.
"Persistent Services: Deploy Web Apps with Automatic HTTPS"

December 21, 2025

Persistent Services: Deploy Web Apps with Automatic HTTPS

Sessions are great for interactive work, but what if you need something that stays running? A webhook receiver. A demo app. A quick API endpoint. Something you can share with a URL.

Today we’re deep-diving into unsandbox Services - persistent containers with automatic HTTPS and custom domain support.

From Sessions to Services

Sessions are ephemeral by design - they exist while you’re connected. But sometimes you need the opposite: something that keeps running after you disconnect.

Sessions:     Connect → Work → Disconnect → Container destroyed
Services:     Create → Runs forever → Accessible via HTTPS

Services are the “set it and forget it” option. They run in isolated containers just like sessions, but with a key difference: they get a public HTTPS URL.

Creating Your First Service

Let’s deploy a simple Python web server:

un service --name myapi --ports 8000 -n semitrusted \
  --bootstrap 'python3 -m http.server 8000'

That’s it. In about 30 seconds you’ll have:

  • A running container with your server
  • An HTTPS URL: https://myapi.svc.unsandbox.com
  • Automatic SSL certificate (via Let’s Encrypt)
  • Traffic proxied to port 8000 inside your container
Service created successfully
  ID: unsb-service-abc123def456
  Name: myapi
  URL: https://myapi.svc.unsandbox.com
  Status: running

Open that URL in your browser - you’ll see the directory listing from Python’s HTTP server.

Real-World Example: A Webhook Receiver

Let’s build something more useful. Say you need to receive webhooks from Stripe, GitHub, or any external service. You need:

  1. A public HTTPS endpoint (webhooks require HTTPS)
  2. Something to log incoming requests
  3. A way to inspect what was received

Here’s a simple Flask webhook receiver:

# Create a bootstrap script
cat > /tmp/webhook-server.sh << 'EOF'
#!/bin/bash
pip install flask
cat > /app/server.py << 'PYTHON'
from flask import Flask, request, jsonify
import json
from datetime import datetime

app = Flask(__name__)
webhooks = []

@app.route('/webhook', methods=['POST'])
def receive_webhook():
    data = {
        'timestamp': datetime.now().isoformat(),
        'headers': dict(request.headers),
        'body': request.get_json(force=True, silent=True) or request.data.decode()
    }
    webhooks.append(data)
    print(f"Received webhook: {json.dumps(data, indent=2)}")
    return jsonify({'status': 'received'}), 200

@app.route('/webhooks', methods=['GET'])
def list_webhooks():
    return jsonify(webhooks)

@app.route('/health', methods=['GET'])
def health():
    return jsonify({'status': 'ok', 'count': len(webhooks)})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)
PYTHON
mkdir -p /app
python3 /app/server.py
EOF

# Deploy it
un service --name webhooks --ports 8000 -n semitrusted \
  --bootstrap /tmp/webhook-server.sh

Now you have:

  • https://webhooks.svc.unsandbox.com/webhook - POST webhooks here
  • https://webhooks.svc.unsandbox.com/webhooks - GET to see received webhooks
  • https://webhooks.svc.unsandbox.com/health - Health check

Test it:

# Send a test webhook
curl -X POST https://webhooks.svc.unsandbox.com/webhook \
  -H "Content-Type: application/json" \
  -d '{"event": "test", "data": {"message": "hello"}}'

# Check what was received
curl https://webhooks.svc.unsandbox.com/webhooks | jq

Point your Stripe/GitHub/etc webhook settings at https://webhooks.svc.unsandbox.com/webhook and you’re ready to debug.

Custom Domains

Don’t want to use *.svc.unsandbox.com? Bring your own domain:

un service --name blog --ports 8000 -n semitrusted \
  --domains blog.example.com,www.example.com \
  --bootstrap './start-blog.sh'

Setup:

  1. Add a CNAME record: blog.example.com → svc.unsandbox.com
  2. We’ll automatically provision an SSL certificate
  3. Your service is live at https://blog.example.com

Multiple domains work too - great for www and naked domain handling.

Managing Services

List All Services

$ un service --list

Services: 3

SERVICE ID                    NAME         STATUS     PORTS
unsb-service-abc123           webhooks     running    8000
unsb-service-def456           myapi        sleeping   8000
unsb-service-ghi789           demo         running    3000,8080

Check Service Details

$ un service --info webhooks

Service: webhooks
  ID: unsb-service-abc123def456
  Status: running
  Ports: 8000
  URL: https://webhooks.svc.unsandbox.com
  Created: 2025-12-21 10:30:00 UTC
  Last Activity: 2025-12-21 14:22:15 UTC

View Bootstrap Logs

$ un service --logs webhooks

[2025-12-21 10:30:05] Installing flask...
[2025-12-21 10:30:12] Successfully installed flask-3.0.0
[2025-12-21 10:30:13] * Running on http://0.0.0.0:8000
[2025-12-21 10:30:45] Received webhook: {"event": "test"...}

Run Commands in a Running Service

Need to debug something? Execute commands directly:

# Check what's running
un service --execute webhooks 'ps aux'

# View recent logs
un service --execute webhooks 'tail -50 /app/server.log'

# Install a debugging tool
un service --execute webhooks 'pip install ipython'

Sleep and Wake: Save Resources

Services auto-sleep after a period of inactivity (configurable). When sleeping:

  • Container is frozen (state preserved)
  • No resource usage
  • First request wakes it (~2 seconds)

Manual control:

# Put a service to sleep
un service --sleep webhooks

# Wake it up
un service --wake webhooks

This is perfect for development services you use intermittently.

Redeploying and Upgrading

Changed your bootstrap script? Redeploy without destroying state:

un service --redeploy webhooks --bootstrap /tmp/new-bootstrap.sh

The service restarts with the new bootstrap. For true blue-green deploys, create a new service and switch DNS.

Example: Static Site with Live Reload

Here’s a pattern for previewing a static site:

cat > /tmp/static-server.sh << 'EOF'
#!/bin/bash
pip install watchdog livereload
cat > /app/serve.py << 'PYTHON'
from livereload import Server
server = Server()
server.watch('/app/public/')
server.serve(root='/app/public', port=8000, host='0.0.0.0')
PYTHON

mkdir -p /app/public
echo "<h1>Hello from unsandbox!</h1>" > /app/public/index.html
python3 /app/serve.py
EOF

un service --name preview --ports 8000 -n semitrusted \
  --bootstrap /tmp/static-server.sh

Now https://preview.svc.unsandbox.com serves your static site. Upload new files via --execute:

un service --execute preview 'cat > /app/public/about.html' < about.html

API Reference

Create Service

POST /services
{
  "name": "myservice",           # becomes myservice.svc.unsandbox.com
  "ports": [8000],               # ports to expose
  "network_mode": "semitrusted", # required for outbound network
  "bootstrap": "python3 app.py", # command or script content
  "custom_domains": ["example.com"],  # optional
  "idle_timeout": 3600           # seconds before auto-sleep (optional)
}

Response:
{
  "service_id": "unsb-service-abc123",
  "name": "myservice",
  "url": "https://myservice.svc.unsandbox.com",
  "status": "starting"
}

List Services

GET /services

Response:
{
  "services": [...],
  "count": 3
}

Service Operations

DELETE /services/:id                    # Destroy service
POST /services/:id/sleep                # Freeze service
POST /services/:id/wake                 # Unfreeze service
POST /services/:id/redeploy             # Restart with new bootstrap
POST /services/:id/execute              # Run command in container
GET /services/:id/logs                  # Get bootstrap logs

Security Model

Services run in isolated containers, just like sessions:

  • Network: Services use semitrusted mode (outbound network allowed)
  • Inbound: Only specified ports are exposed, via HTTPS proxy
  • Resources: CPU/memory limits per container
  • Isolation: Each service in its own container, no shared state

Traffic flow:

Client → HTTPS (TLS termination) → Proxy → Container:port

All traffic is encrypted. The proxy handles SSL certificates automatically.

Pricing

Services consume compute time like sessions. A running service uses 1 slot of your concurrency limit. Sleeping services use zero. Wake-on-request means you only pay for actual usage.

CLI Quick Reference

# Create services
un service --name myapp --ports 8000 --bootstrap "python app.py"
un service --name api --ports 3000,8080 --bootstrap ./setup.sh
un service --name blog --ports 80 --domains blog.example.com -n semitrusted

# Manage services
un service --list                    # list all services
un service --info myapp              # get details
un service --logs myapp              # view bootstrap output
un service --execute myapp 'cmd'     # run command in container

# Lifecycle
un service --sleep myapp             # freeze (save resources)
un service --wake myapp              # unfreeze
un service --redeploy myapp --bootstrap ./new-setup.sh
un service --destroy myapp           # permanent deletion

What to Build

Services are perfect for:

  • Webhook receivers - Debug integrations with external services
  • Demo apps - Share prototypes with a real URL
  • Development previews - Test before deploying to production
  • API mocks - Simulate external services for testing
  • Documentation sites - Host generated docs
  • Bots and workers - Long-running background processes

Get Started

  1. Get the CLI:

    curl -L https://unsandbox.com/cli/un -o un && chmod +x un
  2. Set your API key:

    export UNSANDBOX_API_KEY=your_key_here
  3. Create a service:

    un service --name hello --ports 8000 -n semitrusted \
      --bootstrap 'echo "Hello World" > /tmp/index.html && python3 -m http.server 8000 --directory /tmp'
  4. Visit your URL:

    https://hello.svc.unsandbox.com

What will you deploy?


Questions? Issues? Open a ticket or reach out on Discord.