Use Synous

Use OpenSSH to give your local service a temporary public HTTPS URL. You don’t need to install a client.

Create a public URL

  1. Start your local service. This example uses localhost:8080.

  2. Connect to Synous.

    ssh -T -R 80:localhost:8080 t.synous.dev
  3. If SSH prints an authorization link, open it and sign in with GitHub. A connection without a key can be allowed once. An unknown key can be allowed once, for 24 hours, for 30 days, or forever.

  4. Open the printed public URL. Keep SSH connected while you use the route.

    Public: https://otter-lake.synous.dev
    Press Ctrl-C to stop.
Protect your local service.

Anyone who knows the active URL can send requests to it unless the route is private. A private route requires sign-in.

Authentication

Synous associates every tunnel with a GitHub account and chooses the authentication path automatically:

The Once choice applies only to the waiting connection. The other choices save an offered key for that account until their expiration, and Forever keeps it until it is revoked. A no-key approval cannot be saved; reconnecting requires another approval.

To explicitly connect without offering a public-key identity:

ssh -T -o PubkeyAuthentication=no \
  -o PreferredAuthentications=keyboard-interactive \
  -R 80:localhost:8080 t.synous.dev

You can also authenticate directly with a key already registered to GitHub by including your GitHub username:

ssh -T -R 80:localhost:8080 GITHUB_USERNAME@t.synous.dev

If OpenSSH offers the wrong key, select the key explicitly:

ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes -T \
  -R 80:localhost:8080 GITHUB_USERNAME@t.synous.dev

If an environment needs a disposable conventional identity, this one-liner creates an Ed25519 key in a temporary directory, uses it for the tunnel, and deletes it when SSH exits:

d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; ssh-keygen -q -t ed25519 -N '' -f "$d/key"; ssh -T -i "$d/key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -R 80:localhost:8080 t.synous.dev

For unattended keyless automation, sign in to the dashboard and create a single-use syn_... credential. Put that credential before @t.synous.dev in the SSH command. It is a bearer secret, expires after 10 minutes, and is consumed when SSH connects.

SSH session

When you connect from a terminal, Synous shows an interactive view of the public URL and recent requests. Press q or Ctrl-C to disconnect. Without an allocated terminal, Synous prints the same information as line-oriented output.

Pass options to the connect command, which runs by default:

OptionEffect
--name NAMEUse the stable hostname NAME-<github-user>.synous.dev. NAME is 1 to 23 letters or digits.
--newDraw a new hostname instead of resuming a held one.
--privateAllow only your GitHub account to open the route.
--allow LOGIN,...Also allow these GitHub logins. This option implies --private and is repeatable.
--auth USER:PASSWORDAlso allow one HTTP Basic credential. This option implies --private.
--quietHide per-request access log lines from the SSH output. The dashboard still records recent requests.
ssh -T -R 80:localhost:8080 t.synous.dev connect --name api --private --quiet

Write connect before the options. The word stops the local ssh client from reading the options as its own, and ssh -T -R 80:localhost:8080 t.synous.dev alone still runs connect.

Run ssh t.synous.dev help to list SSH session options. The help command doesn’t require a remote forward. A client that opens no session, such as ssh -N, can’t pass options. It receives a hostname that you can see only in the dashboard.

Private routes

Routes are public by default. Add an access option to the connect command:

ssh -T -R 80:localhost:8080 t.synous.dev connect --private
ssh -T -R 80:localhost:8080 t.synous.dev connect --allow alice,bob
ssh -T -R 80:localhost:8080 t.synous.dev connect --auth demo:demo-password

--private allows only the route owner. --allow LOGIN,... also allows the listed GitHub logins. The owner is always allowed. --allow is repeatable.

--auth USER:PASSWORD also allows one HTTP Basic credential. The password appears in your shell history and can appear in the process list. Use --auth for demos, not for secrets.

When a browser opens a private route, Synous shows a page with a Sign in with GitHub button. After sign-in, Synous returns the browser to the original route and path. The route session lasts for 12 hours or until the route ends.

Your local service receives these headers on an authenticated private-route request:

Synous removes the Basic Authorization header that authenticates a request before it proxies the request. Other Authorization headers pass through unchanged. Synous reserves /.synous-basic and the /.synous/ path prefix for sign-in on private routes. A public route receives these paths unchanged.

Route cookies

Synous uses host-only cookies to authenticate the dashboard and private routes. Its dashboard and private-route session cookies are signed. A cookie signature prevents someone from changing the signed contents; it doesn’t encrypt the contents or make a copied, unexpired cookie harmless. Signing out of the dashboard doesn’t sign the browser out of private routes.

Before forwarding any public or private request, Synous removes every cookie matching __Host-synous-*—that is, every cookie whose case-sensitive name starts with __Host-synous-. The local service receives authenticated X-Synous-* identity headers instead of Synous credentials. Other application cookies pass through unchanged.

When the local service returns a valid Set-Cookie header with a Domain that matches the public route, Synous removes Domain before sending the response to the browser. This makes the HTTP-set application cookie host-only to that exact route hostname. Synous drops malformed cookies, cookies for unrelated domains, and cookies that use the reserved __Host-synous-* namespace.

This response rewriting can’t intercept JavaScript calls to document.cookie. While routes share synous.dev, route applications must not set Domain=synous.dev. Generated hostnames can be reassigned after their 10-minute hold, so retained application cookies or browser storage for an exact generated hostname might reach a later tunnel. Don’t treat a generated hostname as a permanent browser-storage boundary.

Backend protocols

Choose the remote-forward port based on how your local service accepts traffic. Synous supports only remote ports 80 and 443.

Local serviceRemote forwardBackend connection
HTTP or WebSocket -R 80:localhost:8080 Cleartext HTTP
HTTPS or secure WebSocket -R 443:localhost:8443 TLS with support for self-signed certificates

Synous supports HTTP/1.1, HTTP/2, streaming, server-sent events, WebSockets, protocol upgrades, and gRPC. Use remote port 80 for a cleartext gRPC backend and port 443 for a TLS gRPC backend.

Request data

Your local service receives the public host, path, and standard X-Forwarded-* headers. Synous also sets these protected headers:

Synous removes client-supplied X-Synous-* headers before it adds trusted values.

The dashboard keeps up to 100 completed request records for each active route. A record includes the method, URI including the query string, client IP address, status, duration, and byte counts. It doesn’t include headers or bodies.

Route lifetime

Keep secrets out of request paths and query strings. For more information about data handling, see the Synous privacy policy.

Errors

StatusMeaningAction
404The route isn’t active.Check the SSH connection and use the latest URL.
502The local service didn’t accept the connection.Check the local port and backend protocol.
503Synous is temporarily at capacity.Retry after the interval in Retry-After.
504The local forwarding stream timed out.Check the SSH client and local service, and then retry.

A route supports 16 active requests by default. A long-lived stream or WebSocket uses one slot until it closes.