Skip to content

Conversation

@hiroTamada
Copy link
Contributor

@hiroTamada hiroTamada commented Jan 16, 2026

Summary

1. Fix HTTPS redirect loop

When redirect_http: true is enabled for a TLS ingress, the generated Caddy redirect route was matching all requests (both HTTP and HTTPS) because it only checked the hostname. This caused HTTPS requests to be caught in an infinite redirect loop.

Fix: Add "protocol": "http" matcher to redirect routes so they only match HTTP requests.

2. Add API_HOSTNAME config to expose Hypeman API via Caddy

Add configuration options to expose the Hypeman API through Caddy's ingress routing, separate from the instance ingress system.

Configuration:

# /etc/hypeman/config
API_HOSTNAME=api.dev-yul-hypeman-0.kernel.sh  # hostname for API access
API_TLS=true                                    # enable TLS (default: true)
API_REDIRECT_HTTP=true                          # redirect HTTP->HTTPS (default: true)

When API_HOSTNAME is set, Caddy automatically adds a static route that proxies requests to localhost:8080 (the Hypeman API).

Result:

https://api.dev-yul-hypeman-0.kernel.sh/health  →  localhost:8080/health
https://api.dev-yul-hypeman-0.kernel.sh/instances  →  localhost:8080/instances

This is the right approach because:

  • The API ingress is not controlled by ingress rules (avoids chicken-and-egg problem)
  • Configuration is declarative (set once in config, not via API call)
  • Keeps instance ingress system focused on VM routing

Test plan

  • Create a TLS ingress with redirect_http: true
  • Verify HTTP requests get redirected to HTTPS (301)
  • Verify HTTPS requests pass through to the backend (no redirect loop)
  • Set API_HOSTNAME config and restart Hypeman
  • Verify https://api.<hostname>/health returns API response

Note

Introduces API ingress and resolves redirect loop issues while updating wiring and tests.

  • New API ingress: APIIngressConfig and API_HOSTNAME (API_TLS, API_REDIRECT_HTTP) to proxy the Hypeman API directly to 127.0.0.1:<port>; route prepended to avoid wildcard conflicts; reserved hostname validation in manager.
  • Redirect loop fix: Redirect routes now include "protocol": "http" so HTTPS traffic is not re-matched.
  • Wiring: config.Load() reads new vars; providers.ProvideIngressManager parses API port and sets APIIngress; CaddyConfigGenerator and Manager constructors updated to accept APIIngressConfig.
  • Tests updated: Adjusted generator constructor calls and assertions for new behavior (API ingress, HTTP-only redirects).

Written by Cursor Bugbot for commit 081cb53. This will update automatically on new commits. Configure here.

When redirect_http is enabled for a TLS ingress, the generated Caddy
redirect route was matching all requests (both HTTP and HTTPS) because
it only checked the hostname. This caused HTTPS requests to be caught
in an infinite redirect loop.

Add "protocol": "http" matcher to redirect routes so they only match
HTTP requests, allowing HTTPS requests to pass through to the reverse
proxy route.
@hiroTamada hiroTamada changed the title fix: prevent HTTPS redirect loop in ingress routes fix: prevent HTTPS redirect loop and add _api target for localhost routing Jan 16, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Add configuration options to expose the Hypeman API through Caddy's
ingress routing, separate from the instance ingress system.

Configuration:
- API_HOSTNAME: hostname for API access (e.g., api.hostname.kernel.sh)
- API_TLS: enable TLS for API hostname (default: true)
- API_REDIRECT_HTTP: redirect HTTP to HTTPS (default: true)

When API_HOSTNAME is set, Caddy automatically adds a route that proxies
requests to localhost:PORT (the Hypeman API). This allows the API to be
accessed via HTTPS without requiring a separate ingress rule.

Example:
  API_HOSTNAME=api.dev-yul-hypeman-0.kernel.sh
  API_TLS=true

Results in: https://api.dev-yul-hypeman-0.kernel.sh/ -> localhost:8080
@hiroTamada hiroTamada force-pushed the fix/ingress-redirect-loop branch from a43a262 to 7c07690 Compare January 16, 2026 19:37
@hiroTamada hiroTamada changed the title fix: prevent HTTPS redirect loop and add _api target for localhost routing fix: prevent HTTPS redirect loop & add API_HOSTNAME config Jan 16, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

hiroTamada and others added 2 commits January 16, 2026 14:50
Add validation to reject ingress creation when the hostname matches the
configured API_HOSTNAME. This prevents users from hijacking API traffic
by creating an ingress with the same hostname.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

// Add TLS configuration for API hostname
if g.apiIngress.TLS {
listenPorts[443] = true
tlsHostnames = append(tlsHostnames, g.apiIngress.Hostname)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API ingress TLS lacks ACME configuration validation

Medium Severity

When API_HOSTNAME is set, API_TLS defaults to true, causing the API hostname to be added to tlsHostnames and Caddy to listen on port 443. However, unlike instance ingress TLS (which validates that ACME is configured and returns a clear error), there's no validation for the API ingress. If ACME isn't configured, no TLS automation is generated (line 431 requires IsTLSConfigured()), so Caddy will attempt to serve HTTPS using its default ACME behavior (HTTP-01 challenge), which may fail silently in many environments.

Additional Locations (1)

Fix in Cursor Fix in Web

API routes must come before wildcard routes in Caddy config, otherwise
wildcards like *.example.com will match api.example.com and try to
resolve "api" as a VM instance (resulting in 503).
Move the API hostname conflict check earlier in the validation flow
so users get a clear "reserved for API" error instead of a confusing
"instance not found" error.
@hiroTamada
Copy link
Contributor Author

Addressing Bugbot Comments

Issues 1 & 2: _api target code

Status: Fixed

The _api target approach was abandoned in favor of API_HOSTNAME configuration. The dead code (TargetAPI, IsLocalTarget()) has been removed from types.go. These comments reference an older commit.

Issue 3: User ingresses can shadow API hostname

Status: Fixed (commit fbfc60e)

Added conflict check in manager.go that rejects ingress creation when hostname matches API_HOSTNAME:

if m.config.APIIngress.IsEnabled() && rule.Match.Hostname == m.config.APIIngress.Hostname {
    return nil, fmt.Errorf("%w: hostname %q is reserved for the Hypeman API", ErrHostnameInUse, rule.Match.Hostname)
}

Issue 4: API ingress TLS lacks ACME validation

Status: Acceptable

In production, ACME is always configured via Ansible (TLS_ALLOWED_DOMAINS, Cloudflare DNS credentials). If ACME isn't configured, Caddy falls back to HTTP-01 challenge which works for most cases. Could add a warning log in a follow-up PR.

Issue 5: Pattern wildcards can shadow API hostname

Status: Fixed (commit 80cd4ae)

API routes are now prepended to the routes list, ensuring they take precedence over wildcards:

// Prepend API route so it takes precedence over wildcards
routes = append([]interface{}{apiRoute}, routes...)

Verified on staging - API route comes before wildcard:

Route 0: api.dev-yul-hypeman-0.kernel.sh  (API)
Route 1: *.dev-yul-hypeman-0.kernel.sh    (wildcard)

Issue 6: Missing startup validation for API hostname conflicts

Status: Acceptable

Since API routes are now prepended (fix for issue 5), the API will always be accessible even if a conflicting ingress exists. The ingress would simply be unreachable on that hostname. Could add a warning log in Initialize() in a follow-up PR.


Tested on staging:

  • ✅ HTTPS redirect loop fix working
  • ✅ Wildcard ingress routing to instances
  • https://api.dev-yul-hypeman-0.kernel.sh/health returns {"status":"ok"}
  • ✅ HTTP redirects to HTTPS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants