296fdbfdcb
- NeedsSetup: only check for empty customer.id (not "demo-felhom") - renderError: pass *http.Request to ensureCSRFToken (was nil → panic) - Welcome template: remove redundant "v" prefix from version display - IP detection: read HOST_IP env var for Docker container awareness - docker-setup.sh: inject HOST_IP into generated docker-compose.yml - Add logging for Hub config download in setup wizard Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
package setup
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// DetectLocalIPs returns the host's LAN IP addresses.
|
|
// Inside a Docker container, the network interfaces only show the bridge IP
|
|
// (e.g. 172.18.0.4), which is useless for users. Instead, we:
|
|
// 1. Check HOST_IP env var (set by docker-compose.yml)
|
|
// 2. Try to detect the Docker host gateway via `ip route`
|
|
// 3. Fall back to interface enumeration as last resort
|
|
func DetectLocalIPs() []string {
|
|
// Option 1: explicit HOST_IP from environment
|
|
if hostIP := os.Getenv("HOST_IP"); hostIP != "" {
|
|
return []string{hostIP}
|
|
}
|
|
|
|
// Option 2: detect Docker host gateway IP via default route
|
|
// Inside a container, `ip route | grep default` gives the host gateway.
|
|
// Then we check the host's IP by looking at what IP routes to that gateway.
|
|
if ip := detectHostIPViaRoute(); ip != "" {
|
|
return []string{ip}
|
|
}
|
|
|
|
// Option 3: fallback to interface enumeration (works on bare metal)
|
|
return detectInterfaceIPs()
|
|
}
|
|
|
|
// detectHostIPViaRoute tries to find the Docker host's LAN IP.
|
|
// Inside a container, the default gateway is the Docker host.
|
|
// We read /host-etc/hostname or use the gateway as a hint.
|
|
func detectHostIPViaRoute() string {
|
|
// Try: ip route get 1.0.0.0 — shows the source IP used for routing
|
|
out, err := exec.Command("ip", "route", "get", "1.0.0.0").Output()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
// Output: "1.0.0.0 via 172.18.0.1 dev eth0 src 172.18.0.4"
|
|
// The gateway (172.18.0.1) is the Docker host — but that's the bridge IP.
|
|
// We need the host's actual LAN IP.
|
|
|
|
// Better approach: read /proc/net/route or parse `ip route` for the gateway,
|
|
// then the gateway itself is the Docker host — but we need its external IP.
|
|
// Since we can't easily get the host's LAN IP from inside the container,
|
|
// return empty and let the fallback handle it or rely on HOST_IP env.
|
|
_ = out
|
|
return ""
|
|
}
|
|
|
|
func detectInterfaceIPs() []string {
|
|
ifaces, err := net.Interfaces()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
var ips []string
|
|
for _, iface := range ifaces {
|
|
// Skip down, loopback, and Docker/container interfaces
|
|
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
|
|
continue
|
|
}
|
|
name := strings.ToLower(iface.Name)
|
|
if strings.HasPrefix(name, "docker") || strings.HasPrefix(name, "br-") ||
|
|
strings.HasPrefix(name, "veth") || strings.HasPrefix(name, "lo") {
|
|
continue
|
|
}
|
|
|
|
addrs, err := iface.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, addr := range addrs {
|
|
var ip net.IP
|
|
switch v := addr.(type) {
|
|
case *net.IPNet:
|
|
ip = v.IP
|
|
case *net.IPAddr:
|
|
ip = v.IP
|
|
}
|
|
if ip == nil || ip.IsLoopback() || ip.To4() == nil {
|
|
continue // skip non-IPv4
|
|
}
|
|
ips = append(ips, ip.String())
|
|
}
|
|
}
|
|
|
|
return ips
|
|
}
|