Listen on 0.0.0.0 by default and log LAN addresses

- New CANON_HOST (default 0.0.0.0; 127.0.0.1 keeps it on one machine)
- On start, log the http:// addresses other devices can use, skipping
  Docker/VM bridge interfaces
- docker-compose publishes 0.0.0.0:4242 explicitly
- README: opening Canon from other devices and firewall note

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-24 18:05:20 -07:00
1 parent 7320e3f707
commit bcc5e69094
5 files changed
+66 -2

No files matched your search

+48
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"log/slog"
"math/big"
"net"
"net/http"
"os"
"os/signal"
@@ -93,6 +94,7 @@ func run(log *slog.Logger) error {
errc := make(chan error, 1)
go func() {
log.Info("Canon is running", "addr", cfg.ListenAddr, "data", cfg.DataDir, "version", version)
logURLs(log, cfg)
errc <- httpSrv.ListenAndServe()
}()
select {
@@ -149,3 +151,49 @@ func setupCode() string {
}
return string(b[:4]) + "-" + string(b[4:])
}
// logURLs prints the addresses other devices can use to reach Canon.
func logURLs(log *slog.Logger, cfg config.Config) {
if cfg.Host != "0.0.0.0" && cfg.Host != "" && cfg.Host != "::" {
log.Info("open Canon at", "url", "http://"+net.JoinHostPort(cfg.Host, cfg.Port))
return
}
// Inside Docker the container's own addresses aren't reachable from the
// network; the host's address and published port are what matter.
if _, err := os.Stat("/.dockerenv"); err == nil {
log.Info("listening on all interfaces; open http://<this computer's IP>:<published port> from any device on your network")
return
}
log.Info("open Canon at", "url", "http://localhost:"+cfg.Port)
ifaces, err := net.Interfaces()
if err != nil {
return
}
for _, iface := range ifaces {
// Skip interfaces that are down and container/VM bridges, which
// other devices can't reach.
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 || isVirtualBridge(iface.Name) {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok || ipnet.IP.To4() == nil || ipnet.IP.IsLinkLocalUnicast() {
continue
}
log.Info("open Canon on your network at", "url", "http://"+net.JoinHostPort(ipnet.IP.String(), cfg.Port))
}
}
}
func isVirtualBridge(name string) bool {
for _, prefix := range []string{"docker", "br-", "veth", "virbr", "cni", "flannel", "podman"} {
if strings.HasPrefix(name, prefix) {
return true
}
}
return false
}