Documentation
¶
Overview ¶
Package proxy gives every bay its own browser origin.
This is a correctness feature, not cosmetics. Browsers scope cookies, localStorage, IndexedDB and service worker registrations by host and deliberately ignore the port, so two bays served from localhost:3000 and localhost:3001 share one storage partition. Log into one and you are logged into the other; log out of one and the other's session evaporates. The resulting bugs only reproduce when two bays are running, which is exactly when a developer is least able to reason about them.
Distinct hostnames eliminate the whole class.
Two implementation notes explain the shape of this package.
The proxy runs as a container rather than in the daemon because macOS has no setcap and no unprivileged-port sysctl, and pf rules need root and do not survive a reboot. Publishing :80 from a container makes Docker's already-root helper perform the privileged bind, so devbay itself never needs sudo.
The proxy joins each bay's network rather than reaching services through the host, because published ports are bound to loopback and a container cannot reach the host's loopback. Publishing on 0.0.0.0 to make that work would put every bay, and every credential it holds, on the local network.
Index ¶
- Constants
- type Proxy
- func (p *Proxy) Attach(ctx context.Context, networkName string) error
- func (p *Proxy) ClearRoutes(ctx context.Context, project, bay string) error
- func (p *Proxy) Detach(ctx context.Context, networkName string) error
- func (p *Proxy) Ensure(ctx context.Context, httpPort, adminPort int) error
- func (p *Proxy) Routes() []Route
- func (p *Proxy) SetRoutes(ctx context.Context, project, bay string, routes []Route) error
- func (p *Proxy) Stop(ctx context.Context) error
- type Route
Constants ¶
const ( // Image is the proxy image. Caddy is used rather than a hand-written // reverse proxy because WebSocket upgrades, HTTP/2, and a local // certificate authority are all requirements here and all solved problems // there. Image = "caddy:2-alpine" // ContainerName is shared by every bay; there is one proxy per machine. ContainerName = "devbay-proxy" // AdminPort is Caddy's config API inside the container. AdminPort = 2019 // LabelManaged marks the proxy container. LabelManaged = "dev.devbay.proxy" )
const BindEnv = "DEVBAY_PROXY_BIND"
BindEnv names the variable that overrides what the proxy binds to.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Proxy ¶
type Proxy struct {
// HTTPPort is the host port :80 is published on. It falls back to 8080
// when 80 cannot be bound, which keeps devbay usable rather than refusing
// to start.
HTTPPort int
Log func(format string, args ...any)
// contains filtered or unexported fields
}
Proxy manages the shared reverse proxy container.
func (*Proxy) ClearRoutes ¶
ClearRoutes removes a bay's routes.
func (*Proxy) Detach ¶
Detach leaves a bay's network. Teardown must call this before removing the network, or Docker refuses because the endpoint is still active.
func (*Proxy) Ensure ¶
Ensure starts the proxy if it is not already running.
httpPort is the host port to serve on; 0 means try 80 and fall back to 8080. adminPort is where Caddy's config API is published, on loopback only.
type Route ¶
type Route struct {
// Host is the full hostname, e.g. add-oauth.acme.localhost.
Host string
// Upstream is the container-network address, e.g. web:3000. The proxy
// resolves it over the bay network it is attached to.
Upstream string
// Bay and Project identify the owner, so routes can be replaced per bay.
Project string
Bay string
}
Route sends one hostname to one container port.