URLs, destinations, and origins

On this page

  1. Destination forms
  2. Unix socket URLs
  3. Remote loopback TCP
  4. Browser origin and storage
  5. Friendly names and cross-application links
  6. Source references

The browser loads ordinary HTTP(S) URLs. The proxy endpoint and the page’s destination URL are different addresses: configure the browser to contact the local proxy at 127.0.0.1:<listen_port>, then navigate to the remote application’s URL. Do not replace the page host with the proxy’s localhost address.

Destination forms

Host presented to the proxy Meaning
Ordinary hostname or IP address TCP destination from the proxy’s pool’s SSH server. The URL port is the destination port. Hostname resolution is remote.
3000.localhost.outerssh.invalid TCP 127.0.0.1:3000 on the proxy’s pool’s server.
<encoded-path>.unix.outerssh.invalid An absolute Unix socket path on the proxy’s pool’s server.

Encoded destinations require no DNS and no route-registration call. OuterSSH recognizes and decodes them for each incoming connection, including subresources and WebSockets. The proxy still applies socket authorization and chooses direct forwarding or a bridge.

Each proxy uses the session pool supplied at creation. Every destination, whether encoded or an ordinary hostname, is reached through that pool. URLs contain no server identifier.

Unix socket URLs

The application-facing convention is:

http+unix://%2Frun%2Fuser%2F1000%2Fapp.sock/path?query=value#section

The percent-encoded authority is the absolute socket path. /path, the query, and the fragment belong to the HTTP resource, not to the socket filename. The host application parses this convention and converts it to:

http://<encoded-path>.unix.outerssh.invalid/path?query=value#section

http+unix is not a scheme that the C proxy or browser engine handles natively. Intercept these navigations, encode the destination, and load the resulting HTTP URL. For subresource URLs, provide the encoded HTTP form; installing a navigation handler alone does not make fetch("http+unix://…") work.

Use the header-only helpers in SSHProxyAddress.h, which need no SSH runtime:

char host[OUTERSSH_PROXY_SOCKET_HOST_CAPACITY];
size_t host_length;
static const char path[] = "/run/user/1000/app.sock";
bool encoded = outerssh_proxy_encode_socket_host(
    path, sizeof(path) - 1,
    host, sizeof(host), &host_length);

Check encoded before constructing a URL. Preserve the resource path, query, and fragment when replacing the scheme/authority.

The path’s bytes use unpadded lowercase base32, split into 50-character labels. The full hostname is at most 253 bytes; the output buffer capacity includes its terminating NUL. The helper rejects nonabsolute paths, control bytes, paths over 144 bytes, or names too long for the output buffer. The remote OS imposes its own socket-path limits. Do not truncate or hash paths to make them fit.

Only destination port 80 is accepted for encoded Unix sockets. https://<encoded-socket-host>/ implies port 443 and is rejected; HTTPS-over-Unix is not part of this contract. A fragment is handled by the browser and is never sent to the proxy.

The decoder checks canonical encoding (case-insensitively for DNS spelling), rejecting alternate label splits, padding, and noncanonical trailing bits. Malformed reserved names fail rather than becoming DNS lookups.

Remote loopback TCP

Use outerssh_proxy_encode_loopback_host(port, ...) for remote loopback ports. Ports range from 1 through 65535. The port embedded in the hostname is authoritative for routing:

http://3000.localhost.outerssh.invalid/editor

This reaches remote 127.0.0.1:3000, even though the browser-facing URL uses the HTTP default port. A literal localhost sent through the proxy also refers to the SSH server’s TCP destination, but browsers may bypass proxies for local addresses. Encoded names avoid the browser’s special treatment of local addresses.

Browser origin and storage

The browser applies its normal origin rules to the actual URL’s scheme, hostname, and port. It has no knowledge of the decoded socket path. The same socket path on two remote accounts must not accidentally reuse the same browser storage identity.

Each current Outer Loop adapter uses separate website-data stores or profiles for different servers. Hosts embedding a web view should do the same. Changing the configured proxy does not change a URL’s browser origin; an existing browser using http://localhost:4000 through different proxies would need separate profiles to isolate its stored site data.

Relative URLs retain the current origin. Encoded hostnames must reach the proxy without local DNS resolution.

Outer Loop also recognizes outerloop://navigate?url=…&display=… links. Their URL and friendly display text, icon handling, address-bar editing, and history are product conventions outside OuterSSH. An adapter interprets the link, converts any nested socket URL, and navigates.

The browser may decode synthetic names for user-visible addresses and error messages. It need not tell the proxy about a navigation between endpoints: the next request’s hostname supplies the destination.

Source references