nixfredEXE.DEVFIELD GUIDE · BY NIX UNOFFICIAL
LEARN / PROXY, SHARING, DOMAINS, EMAIL

The network edge: proxy, sharing, login and domains

Every VM is on the internet at https://vmname.exe.xyz/, “with certificates and TLS handled by the HTTPS proxy”. Sites are private until shared, and Login with exe tells your app who is visiting.

Sources: https://exe.dev/docs/proxy, https://exe.dev/docs/sharing, https://exe.dev/docs/login-with-exe, https://exe.dev/docs/cnames, https://exe.dev/docs/internet-access, https://exe.dev/docs/receive-email, https://exe.dev/docs/send-email.

The HTTPS proxy

exe.dev “proxies traffic to https://vmname.exe.xyz/ to your VM seamlessly, handling certificates, TLS termination, and optionally offering basic authentication.”

Which port gets proxied

  • Automatic choice. exe.dev picks from the ports listed under EXPOSE in the image’s Dockerfile. It prefers port 80 and otherwise falls back to the smallest exposed TCP port of 1024 or higher.
  • Choosing a port yourself. Run ssh exe.dev share port <vmname> <port> to change it. This keeps the current visibility setting.
  • exeuntu. On the default image the share port is 8000 (https://exe.dev/docs/migrating-to-exe).

Additional ports

The proxy transparently forwards ports 3000 to 9999, so https://vmname.exe.xyz:3456/ reaches port 3456. “You may only mark a single port public”. The other ports can only be reached by users with access to the VM.

Headers your app receives

HeaderMeaning
X-Forwarded-Protohttps when the client used TLS
X-Forwarded-HostThe full host header (including port) the client requested
X-Forwarded-ForPrior value plus the client IP as seen by exe.dev
X-ExeDev-UserIDStable, unique user ID (only when authenticated)
X-ExeDev-EmailThe user’s email (only when authenticated)

JS dev servers

Next.js 15.2 and later needs allowedDevOrigins: ['my-vm.exe.xyz']. Vite 5 and later needs server.allowedHosts: ['my-vm.exe.xyz'] (https://exe.dev/docs/faq/nextjs-and-friends).

Private by default, then share

“By default, only users with access to the VM can access the HTTP proxy. Users accessing https://vmname.exe.xyz/ for the first time will be redirected to log into exe.dev.”

Access levels

  • Web. Opens the VM’s private HTTPS proxy after the person logs in. “It does not give them a shell.”
  • Root. Web access plus SSH, the browser Terminal and Shelley. “A Root collaborator can read, change, or delete anything inside the VM”. It needs an existing exe.dev account and does not transfer ownership.
GoalCommand
Share web with a person (invites by email)share add <vm> <email>
Give an existing user Rootshare add <vm> <email> --root
Share web with the whole teamshare add <vm> team
Give the whole team Rootshare add <vm> team --root
Share by link (Web only, recipient must register)share add-link <vm>
Revoke a linkshare remove-link <vm> <token>
Make it publicshare set-public <vm>
Make it private againshare set-private <vm>
Downgrade Root to Webshare remove <vm> <email> --root
Remove all accessshare remove <vm> <email>
Inspectshare show <vm>

Two details that come up in conversation:

  • Team shares follow current membership: “new members gain access and former members lose it.”
  • Revoking a link stops new people from using it, but it doesn’t remove people who already accepted.

Team admins can restrict sharing with team settings vm-sharing off|admins-only|all-members (https://exe.dev/docs/teams/sharing-controls).

Login with exe

This feature lets “you build authorization without managing passwords or e-mails yourself.”

  • Private sites always carry the authentication headers, because a visitor must have been shared in to reach the site.
  • Public sites carry the headers only for logged-in users. Send people through https://vmname.exe.xyz/__exe.dev/login?redirect={path} to require an email.
  • Logging out is a POST to https://vmname.exe.xyz/__exe.dev/logout.
  • Local development. Nothing adds the headers on localhost, so the docs suggest mitmdump in reverse mode to inject X-Exedev-Email and X-Exedev-Userid while you test.
# From the docs: allow only listed emails
if ($http_x_exedev_email = "alice@example.com") { set $allowed "true"; }
if ($allowed = "false") { return 403; }

Custom domains

Setting up a custom domain takes two steps:

  1. At your DNS provider, add a CNAME (or an ALIAS/ANAME/flattened CNAME for an apex domain) pointing to vmname.exe.xyz.
  2. Run ssh exe.dev domain add <vm> <domain>.

TLS certificates are issued automatically. Until a domain is registered, requests for it get 421 Misdirected Request.

Other domain commands:

  • List: domain ls <vm> for one VM, or domain ls -a for all of them.
  • Remove: domain rm <vm> <domain>.
  • Wildcard certificates: domain add --wildcard gives you a *.example.com certificate after a one-time delegation of ACME challenges.
  • Wildcard DNS: a wildcard CNAME *.app.example.com plus domain add vmname '*.app.example.com' sends every one-level subdomain to one VM.

The Cloudflare gotcha

Cloudflare defaults DNS records to Proxied (orange cloud). That “replaces your desired CNAME/ALIAS targets with Cloudflare IP addresses, and therefore breaks exe.dev’s custom domain support.” The fix has two parts:

  • Use DNS Only (grey cloud), or keep the proxy and rewrite requests to vmname.exe.xyz with Cloudflare Snippets or Workers. The docs note that “Snippets are a paid feature.”
  • Set CNAME flattening to Flatten CNAME at root. Don’t use “Flatten all CNAMEs”, which “prevents us from learning the VM name.”

Outbound: egress policy

The default policy is all. Setting it to integrations blocks the public internet but keeps exe.dev metadata and attached integration endpoints reachable:

ssh exe.dev egress my-vm integrations
ssh exe.dev new --egress=integrations
ssh exe.dev cp my-vm --egress=integrations   # copies inherit the policy unless set

New VMs use the DNS server at 169.254.169.254. Older VMs need /etc/resolv.conf updated before you restrict egress (https://exe.dev/docs/internet-access).

Email in and out

Receiving

Turn it on with ssh exe.dev share receive-email vmname on. Mail sent to *@vmname.exe.xyz lands in ~/Maildir/new/.

Limits from the docs:

  • No spam, virus or phishing checks.
  • No custom domains yet.
  • 1 MB maximum message size.
  • More than 1,000 files sitting in new/ disables receiving.

Source: https://exe.dev/docs/receive-email.

Sending

Send plain text with POST http://169.254.169.254/gateway/email/send, using the fields to, subject and body. Attachments are supported, and sending is rate-limited. Allowed recipients are:

  • you
  • your team
  • people who logged into your shared VM
  • people who emailed the VM, which is thread-scoped and DKIM-verified

Source: https://exe.dev/docs/send-email.

← VMs, pools and sandboxes · SSH API, HTTPS API, MCP →