# The Hoody Proxy

**Page:** getting-started/proxy

[Download Raw Markdown](./getting-started/proxy.md)

---

# The Hoody Proxy

**Every URL you've been using? The proxy makes it work.**

The Hoody Proxy is the gateway between the outside world and your containers. It handles HTTPS certificates, routes requests to the right service, manages permissions, and preserves real client IPs. All automatically. Every program you run gets HTTPS, HTTP/2, and HTTP/3 (QUIC) — out of the box. No configuration. No cert rotation. No Let's Encrypt dance.

You will never think about a certificate again in your life. It just works.

---

## What the Proxy Does

1. **Automatic HTTPS** — Wildcard TLS certificates for every container URL. No Let's Encrypt setup, no cert rotation, no DNS challenge.

2. **URL routing** — Parses `{projectId}-{containerId}-{service}-{instance}.{serverName}.containers.hoody.icu` and routes to the correct service inside the correct container.

3. **Permission enforcement** — Authentication (JWT, password, IP whitelist, bearer token) checked before any request reaches your container.

4. **Real client IP** — Uses netfilter hooks to preserve the real client IP address. Your application sees the actual visitor, not a proxy address.

5. **Protocol support** — HTTP/1.1, HTTP/2, HTTP/3 (QUIC), and WebSocket upgrades. Real-time terminals and displays work seamlessly.

---

## How URLs Route

When you hit:
```
https://abc123-def456-terminal-1.node-us-1.containers.hoody.icu/api/v1/terminal/execute
```

The proxy:
1. Extracts `abc123` (project), `def456` (container), `terminal-1` (service + instance)
2. Looks up `node-us-1` to find the physical server
3. Routes to `terminal` service instance `1` inside container `def456`
4. Forwards the request with real client IP preserved

All in milliseconds. No configuration on your part.

---

## Custom Domain Aliases

Tired of sharing a URL stuffed with Project and Container IDs? Create an alias — a memorable name (3-61 chars, `a-z`, `0-9`, hyphens) that resolves to a short, clean URL:


  
    ```bash
    # Create a proxy alias
    hoody proxy create \
      --container-id $CONTAINER_ID \
      --program "exec" \
      --alias "my-api" \
      --index 1
    ```
  
  
    ```typescript
    const alias = await client.api.proxyAliases.create({
      container_id: CONTAINER_ID,
      program: 'exec',
      alias: 'my-api',
      index: 1
    });
    // Now https://my-api.{server}.containers.hoody.icu → your exec scripts
    ```
  
  
    ```bash
    curl -X POST https://api.hoody.icu/api/v1/proxy/aliases \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "container_id": "'$CONTAINER_ID'",
        "program": "exec",
        "alias": "my-api",
        "index": 1
      }'
    ```
  



Want a domain you fully own, like `api.myapp.com`? Point its DNS at Hoody and connect it to the container — HTTPS certificates are provisioned automatically. See [Connect a Domain](/foundation/proxy/connect-domain/).


---

## Permissions

By default, container URLs are accessible by anyone who has the URL. The URL itself is unguessable (48+ characters of hex), which provides a baseline of security.

When you're ready to lock things down:


  
    ```bash
    # Require password authentication
    hoody containers proxy permissions replace -c $CONTAINER_ID \
      --project $PROJECT_ID \
      --groups auth='{"type": "password", "password": "my-secret"}' \
      --permissions auth='{"terminal": true, "files": true, "display": true}'

    # Restrict to specific IP addresses
    hoody containers proxy permissions replace -c $CONTAINER_ID \
      --project $PROJECT_ID \
      --groups office='{"type": "ip", "range": "203.0.113.10/32"}' \
      --permissions office='{"terminal": true, "files": true, "display": true}'
    ```
  
  
    ```typescript
    // Require password auth
    await client.api.proxyPermissionsContainer.replace(CONTAINER_ID, {
      project: PROJECT_ID,
      container: CONTAINER_ID,
      groups: { devs: { type: 'password', password: 'my-secret' } },
      permissions: { devs: { terminal: true, files: true, display: true, http: true } },
      default: 'deny'
    });

    // IP restriction
    await client.api.proxyPermissionsContainer.replace(CONTAINER_ID, {
      project: PROJECT_ID,
      container: CONTAINER_ID,
      groups: {
        office_primary: { type: 'ip', range: '203.0.113.10/32' },
        office_subnet: { type: 'ip', range: '198.51.100.0/24' }
      },
      permissions: {
        office_primary: { terminal: true, files: true, display: true, http: true },
        office_subnet: { terminal: true, files: true, display: true, http: true }
      },
      default: 'deny'
    });
    ```
  
  
    ```bash
    # Set password auth
    curl -X PATCH https://api.hoody.icu/api/v1/containers/$CONTAINER_ID/proxy/permissions \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"project":"'$PROJECT_ID'","container":"'$CONTAINER_ID'","groups":{"devs":{"type":"password","password":"my-secret"}},"permissions":{"devs":{"terminal":true,"files":true,"display":true,"http":true}},"default":"deny"}'
    ```
  


One permissions document declares reusable auth groups (password, JWT, IP, token) and grants per-program access to them. Add a program in the `permissions.<group>.<program>` map to let that group in; anything not granted stays at the default policy. Configure once, apply it across whichever services need protection.

---

## The Philosophy: Open by Default

URLs are unguessable. Sharing requires knowing the URL. This means:

- **Development**: No auth friction. Just build.
- **Collaboration**: Share the URL. Everyone's in.
- **Production**: Add authentication when you're ready.

No premature security configuration slowing you down. No "I can't access the dev environment" tickets.

> **The proxy is invisible when you don't need it, and bulletproof when you do.**

**Next:** [Your First API →](/getting-started/your-first-api/)