Documentation
¶
Overview ¶
package unixproxy provides an EXPERIMENTAL reverse proxy to Unix sockets.
The intent of this package is to facilitate local development of distributed systems, by allowing normal HTTP clients that assume TCP (cURL, browsers, etc.) to address localhost servers via semantically-meaningful subdomains rather than opaque port numbers.
For example, rather than addressing your application server as localhost:8081 and your Prometheus instance as localhost:9090, you could use
http://myapp.unixproxy.localhost http://prometheus.unixproxy.localhost
Or, you could have 3 clusters of 3 instances each, addressed as
http://{nyc,lax,fra}.{1,2,3}.unixproxy.localhost
The intermediating reverse-proxy, provided by Handler, works dynamically, without any explicit configuration. See documentation on that type for usage information.
Application servers need to be able to listen on Unix sockets. The ParseURI and ListenURI helpers exist for this purpose. They accept both typical listen addresses e.g. "localhost:8081" or ":8081" as well as e.g. "unix:///tmp/my.sock" as input. Applications can use these helpers to create listeners, and bind HTTP servers to those listeners, rather than using default helpers that assume TCP, like http.ListenAndServe.
cmd/unixproxy is an example program utilizing package unixproxy.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ListenURI ¶
ListenURI is a helper function that parses the provided URI via ParseURI, and returns a net.Listener listening on the parsed network and address.
func NewDNSServer ¶
NewDNSServer returns a DNS server which will listen on addr, and resolve all incoming A, AAAA, and HTTPS requests to localhost. Specifically, it resolves all A and HTTPS queries to the IPv4 address 127.0.0.1, and all AAAA queries to the IPv6 address ::1. It ignores all other request types.
A nil logger parameter is valid and will result in no log output.
This is intended for use on macOS systems, where many applications (including Safari and cURL) perform DNS lookups through a system resolver that ignores /etc/hosts. As a workaround, users can run this (limited) DNS resolver on a specific local port, and configure the system resolver to use it when resolving hosts matching the relevant host string.
Assuming the default host of unixproxy.localhost, and assuming this resolver runs on 127.0.0.1:5354, create /etc/resolver/localhost with the following content.
nameserver 127.0.0.1 port 5354
Then e.g. Safari will resolve any URL ending in .localhost by querying the resolver running on 127.0.0.1:5354. See `man 5 resolver` for more information on the /etc/resolver file format.
func ParseURI ¶
ParseURI parses the given URI to a network and address that can be passed to e.g. net.Listen.
The URI scheme is interpreted as the network, and the host (and port) are interpreted as the address. For example, "tcp://:80" is parsed to a network of "tcp" and an address of ":80", and "unix:///tmp/my.sock" is parsed to a network of "unix" and an address of "/tmp/my.sock".
If the URI doesn't have a scheme, "tcp://" is assumed by default, in an attempt to keep basic compatibilty with common listen addresses like "localhost:8080" or ":9090".
Types ¶
type Handler ¶
type Handler struct { // Root is a valid directory on the local filesystem. The handler will look // in this directory tree, recursively, for destination Unix sockets, when // proxying an incoming request. See [Handler] for more detail. // // Required. Root string // Host is the base/apex domain which the Handler expects to receive as part // of all request Host headers. It should end in .localhost per RFC2606, and // the system should resolve that domain, and all subdomains, to a localhost // IP. Typically, this is done by adding an entry to /etc/hosts as follows. // // 127.0.0.1 localhost # note: separator must be a literal tab // // Modern macOS systems will ignore /etc/hosts in many contexts, see // [NewDNSServer] for a workaround. // // Optional. The default value is "unixproxy.localhost". Host string // ErrorLogWriter is used as the destination writer for the ErrorLog of the // [http.ReverseProxy] used to proxy individual requests. // // Optional. By default, each [http.ReverseProxy] has a nil ErrorLog. ErrorLogWriter io.Writer // contains filtered or unexported fields }
Handler is a reverse proxy to Unix sockets on the local filesystem.
Requests are mapped to sockets based on their Host header. Each sub-domain element underneath the configured Host domain is parsed as a filepath element relative to Root directory. If the resulting filepath identifies a valid Unix socket, the request is proxied to that socket.
As an example, a Handler configured with Host "unixproxy.localhost" and Root "/tmp/abc" would map a request with Host header "foo.bar.unixproxy.localhost" to a socket at "/tmp/abc/foo/bar".
Parameters are evaluated during ServeHTTP.
func (*Handler) ServeHTTP ¶
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. If the request Host header is equal to the Host field (i.e. has no subdomains), ServeHTTP will serve a list of valid subdomains. Otherwise, the request will be proxied to a local Unix domain socket based on its subdomain.