Skip to content

Network and ports

This page is the reference for the network side of a Restow installation: which connections exist, which side opens each one, which protocol and port it uses, and what stops working when a firewall blocks it. Use it to plan the firewall of a dedicated VM at a hosting provider such as Hetzner or Azure, or of a Restow host in your LAN behind a reverse proxy. The short list of published ports is in Ports and roles; everything else is here.

Restow runs as one Docker Compose stack on one host (see One host). Who opens a connection decides which firewall has to allow it:

  • Browsers of administrators and users connect to Caddy, the web edge, over HTTPS on port 443.
  • Agents on servers and clients connect to the same address and port. An agent only connects out. Nothing on the endpoint listens, and the instance never connects to an endpoint: tasks such as “back up now” reach the agent in the answer to its regular contact, every 5 minutes.
  • Proxmox VE nodes connect to the same address and port, like agents, when you back up VMs and containers. The helper on a node only connects out, and the instance never connects to a node (see How Proxmox VE nodes reach their repository).
  • Exchange Online connects to port 25 of the journal receiver, which runs inside the api container, if you use journaling. A mail provider that forwards copies of its mail to the archive (since 0.4.4) connects to the same port.
  • Microsoft Graph connects to port 443, like a browser, with its change notifications of new mail, if you archive Microsoft 365 mailboxes by Graph (since 0.4.4). This is the only connection that Microsoft opens into the installation (see Microsoft calls the instance). Without it nothing breaks: Restow checks the mailboxes at intervals instead.
  • Let’s Encrypt connects to port 80 (and 443) to validate your domain when Caddy requests a certificate itself.
  • The Docker host mounts file shares (since 0.4.0). For file share backup the Docker host, not a container, connects to your file servers: SMB on TCP 445, NFS on TCP 2049 (see How the instance reaches file servers). The file server opens no connection to Restow.
  • The Restow host connects out to everything else: Microsoft 365, IMAP servers, S3 storage, a mail relay, webhook targets and, when you enable them, update sources. The worker does most of this, the api the rest.
  • The containers talk to each other over the Docker network. None of these ports is published.

Restow contacts no server of the vendor. The license key is verified offline, and the update check is off until an administrator turns it on and sends no data about your installation. See License and editions and Updates.

Components and connections of a Restow installationBrowsers and agents on endpoints connect to the Caddy edge on port 443. Exchange Online connects to the journal receiver in the api container on port 25, an optional feature. Let's Encrypt validates the domain on ports 80 and 443 while Caddy requests certificates over port 443. Caddy forwards to the api on port 3000. The api, worker and scheduler connect to PostgreSQL on port 5432. The updater is optional and reached by the api on port 8090. From the Restow host, connections go out to Microsoft 365 on 443, IMAP servers on 993 or 143, S3 storage on 443, and optionally to a mail relay on 587 or 465, webhook targets and update sources on 443. An NFS share is mounted on the host over port 2049. The local volume needs no network.ClientsYour storageRestow host (Docker Compose)InternetBrowsersadmins, end usersEndpointagent, Linux, macOSno open portNASNFSCaddy edgeTLS, web interface,proxy to the apischedulerno portsworkerno portsapiREST, restic,journal SMTPpostgresPostgreSQL 16, job queueHost mountNFSLocal volumerestow-dataupdateropt-inLet's EncryptcertificatesExchange OnlinejournalingMicrosoft 365Graph, sign-inIMAP serversyour mail hostsS3 storageS3-compatibleMail relaynotificationsWebhook targetsRMM, PSAGitHub, ghcr.ioupdatesHTTPS443HTTPS443ACME443validation80/443SMTP25HTTP3000SQL5432SQL5432SQL5432HTTP8090NFS2049HTTPS443IMAP993/143HTTPS443SMTP587/465HTTP(S)URL portHTTPS443Connection: the dot is the side that opens itOptional feature443PortOptional component
Components and connections. The dot marks the side that opens a connection, the arrowhead the side that accepts it; dashed lines are optional features. The tables below carry the same information.

These are the only connections that anybody opens to the Restow host.

Port Protocol From Needed when If it is closed
443 TCP, HTTPS Browsers of administrators and users, agents on servers and clients, Proxmox VE nodes, Microsoft Graph (change notifications for archive capture, since 0.4.4), Let’s Encrypt (TLS-ALPN validation); behind a reverse proxy: the proxy Always The web interface, the install scripts and every agent and Proxmox VE node are unreachable. Jobs that only talk to Microsoft 365, IMAP or S3 keep running, because the worker needs no inbound connection. Graph capture falls back to checking each mailbox every 15 minutes.
80 TCP, HTTP Let’s Encrypt (HTTP validation), browsers that open an http:// address Public mode, while Caddy manages its own certificate Caddy cannot validate over HTTP and may fail to issue or renew its certificate, and http:// addresses are not redirected. Open it to everyone: Let’s Encrypt validates from several places at once.
25 TCP, SMTP with mandatory STARTTLS Exchange Online; the mail servers of a provider that forwards copies Exchange journaling and forwarded copies only (Business and Service Provider), after you set JOURNAL_SMTP_PORT=25 and JOURNAL_SMTP_BIND=0.0.0.0 No journal reports and no forwarded copies arrive. Exchange Online sends the reports it cannot deliver to your mailbox for undeliverable journal reports; a provider’s server tries again for a while. The port must reach the receiver directly, never through Caddy or an HTTP proxy.
22 TCP, SSH Your administrators To manage the host. This is not a Restow port You manage the host another way, for example through the provider’s console. Allow it only from your own addresses.

Restow does not check who connects to port 25 beyond a rate limit per sender address: it accepts only the journal addresses it knows, and it checks neither SPF nor Microsoft’s address ranges (see Exchange journaling); the limits are 600 connections per minute per sender address and 300 deliveries per minute per archive address, per api process, and can be changed. If you want to restrict the source for journaling, Microsoft lists the addresses it connects from into customer networks on its other endpoints page; check them regularly.

Microsoft calls the instance: Graph change notifications

Section titled “Microsoft calls the instance: Graph change notifications”

Since 0.4.4, archiving Microsoft 365 mailboxes by Graph (Business and Service Provider, see Archiving) is the one feature in which Microsoft opens a connection into your installation. For every archived mailbox Restow asks Microsoft Graph for a change notification; Microsoft then sends an HTTPS POST to these two paths of the public URL when a mail arrives or a subscription needs attention:

  • /api/v1/hooks/graph/notifications
  • /api/v1/hooks/graph/lifecycle

What has to hold:

  • The public URL is https:// on port 443 and names a host that Microsoft can resolve and reach from the internet. A URL with another port, localhost, a private address or a name ending in .local, .internal or .lan gives no notifications. The URL comes from Installation → Server & operation → Server, else from RESTOW_PUBLIC_URL.
  • The certificate is one that Microsoft validates. The edge with its own Let’s Encrypt certificate does. A certificate of Caddy’s internal authority does not, so behind a reverse proxy it is the proxy’s public certificate that Microsoft sees.
  • A reverse proxy passes the two paths through unchanged: POST, the body up to 1 MiB, no sign-in or single sign-on in front of them, no filter on the source address that excludes Microsoft, and an answer in a few seconds (Microsoft waits 3 seconds for a notification and 10 for the validation of a new subscription).
  • No source address list is needed or provided. Restow does not check where a notification comes from; it checks the subscription’s secret and ignores everything else. Do not restrict the two paths by Microsoft address unless you keep the list current yourself.
  • Without an edition that includes capture from the mailbox, the two paths answer 404.

If any of this does not hold, Restow does not fail: it creates no subscription and checks each mailbox for changes every 15 minutes (ARCHIVE_GRAPH_POLL_MINUTES), and the Archive page names the reason (graph.notification_url_unavailable, or graph.subscription_failed when Microsoft refuses a subscription; it is tried again every hour). The outbound side is unchanged: login.microsoftonline.com and graph.microsoft.com on 443.

  • 3000 (api): published on 127.0.0.1 only (RESTOW_API_PORT), for health checks on the host. Caddy reaches it over the Docker network.
  • 5432 (postgres): the release stack does not publish it.
  • 8090 (updater) and 8091 (mounter): not published, only reachable on the Docker network.
  • The journal port while JOURNAL_SMTP_BIND has its default 127.0.0.1.

RESTOW_HTTP_PORT and RESTOW_HTTPS_PORT change the host ports of the edge; an address and a port such as 127.0.0.1:8443 publish it on that interface only. Let’s Encrypt needs the standard ports, so change them only behind another reverse proxy or for a local evaluation.

The Restow host opens these connections. A destination is needed only when you use the feature in the last column.

Destination Port, protocol Why Needed when
login.microsoftonline.com 443, HTTPS Token requests of the backup app, and the admin consent flow Microsoft 365 sources, notification mail through Microsoft Graph
graph.microsoft.com 443, HTTPS Microsoft Graph: directory sync, mail and OneDrive backup and restore; notification mail with MAIL_TRANSPORT=graph Microsoft 365 sources, notification mail through Microsoft Graph
*.sharepoint.com, for OneDrive your tenant’s <tenant>-my.sharepoint.com 443, HTTPS Graph hands out short-lived URLs on these hosts for OneDrive file downloads, and upload sessions for restores OneDrive protection
The IMAP servers you enter The port you enter: 993 (TLS) or 143 (STARTTLS) IMAP backup, restore and Test sign-in; at most two connections per account. IMAP archiving (since 0.4.4) keeps one more open per account with IDLE, up to four in all while a pass and a backup run IMAP sources. Servers on loopback, private or local addresses are refused unless IMAP_ALLOW_PRIVATE_NETWORKS=true or a provider administrator saved the host.
S3-compatible storage 443, HTTPS, or the port in the endpoint URL Backup, restore, archive and the repositories of endpoints An S3 storage target. Since 0.4.0 a new or changed endpoint must use https:// (except to localhost).
Your file servers (the Docker host) TCP 445 (SMB), TCP 2049 (NFS); NFSv3 also 111 (portmapper) and the mount daemon’s port Mounting an SMB share or NFS export read-only for one run of a file share backup, a restore or a copy File shares (since 0.4.0). The connection is made by the Docker host’s kernel, not by a container.
Your mail relay The port you enter in the setup: 587 (STARTTLS) or 465 (implicit TLS); unencrypted only for an internal relay Alerts, reports and invitations MAIL_TRANSPORT=smtp. Not needed with Microsoft Graph sendMail, which uses the two Microsoft rows above.
Webhook targets The port in each URL, http:// or https:// Webhook deliveries from the worker When you register webhooks. Targets on loopback or private networks are refused unless RESTOW_WEBHOOK_ALLOW_PRIVATE=true.
Let’s Encrypt, with ZeroSSL as Caddy’s fallback 443, HTTPS Caddy requests and renews its certificate (ACME) Public mode with the edge managing its own certificate. Not behind a reverse proxy that holds the certificate (from 0.2.0 with RESTOW_EDGE_TLS=internal, or with a plain HTTP hop).
api.github.com, or the host of your own update source 443, HTTPS The update check reads the release list. No data about your installation is sent, and a redirect to another host is not followed. Only after an administrator turns the update check on
ghcr.io, tuf-repo-cdn.sigstore.dev 443, HTTPS The optional updater pulls the images and checks their signatures with cosign, through the Docker daemon of the host Only with the updater profile
github.com, ghcr.io, registry-1.docker.io, tuf-repo-cdn.sigstore.dev, and download.docker.com 443, HTTPS The install script. The last host only when the script installs Docker. An update by hand pulls from ghcr.io and registry-1.docker.io, which serves the postgres image. Installation and updates

Two things are not Restow ports but must work: the DNS resolver of the host (port 53), because every destination above is a name, and a synchronised clock (NTP, UDP 123), because certificate checks and authenticator codes need the right time (see Get started).

Microsoft publishes the endpoints of Microsoft 365 with ports and address ranges on Microsoft 365 URLs and IP address ranges; login.microsoftonline.com, graph.microsoft.com and *.sharepoint.com are listed there for TCP 443. If you restrict outbound traffic to a list, the install script and a manual update need more destinations than daily operation does, so open them for the time you install or update.

The containers of the stack reach each other by service name on the default network of the Compose project. None of these ports is published.

From To Port Protocol What for
caddy api 3000 HTTP /api/*, /agent/*, /install/*, /healthz and /readyz, and a liveness call before every page request. That call is how the maintenance page appears when the api is down.
api, worker, scheduler postgres 5432 PostgreSQL Application data and the job queue, with the three database roles
api updater 8090 HTTP Only with the updater profile (RESTOW_UPDATER_URL, default http://updater:8090)
api, worker mounter 8091 HTTP Only with the mounts profile (RESTOW_MOUNTER_URL, default http://mounter:8091): the api for network shares and the mounter’s status, the worker to start file share runners (since 0.4.0). A shared secret from the volume restow-mounter-shared authenticates the call.
File share runner api 3000 HTTP Over the internal network runners only (RESTOW_MOUNTER_RUNNER_API_URL, default http://api:3000): the runner’s restic repository route and its progress reports, with a credential valid for one run that can only add data (since 0.4.0). The network has no route to the outside, so a runner reaches nothing else.
updater api 3000 HTTP Only with the updater profile: readiness of the new version and, in source mode, the stored token
caddy updater 8090 HTTP One read-only status document (/_maintenance/status) for the maintenance page
worker, api itself random, on 127.0.0.1 HTTP The listener for one restic maintenance operation on an endpoint repository (see How endpoints reach their repository). It never leaves the container.
The host api 3000 on 127.0.0.1 HTTP Health checks (RESTOW_API_PORT). This is not a connection between containers.

worker and scheduler expose no ports, and nothing connects to them. They connect to PostgreSQL, and the worker connects to the outbound destinations above for its jobs. The roles do not call each other: the api and the scheduler put jobs into the queue in PostgreSQL (pg-boss), the worker polls that queue (WORKER_POLL_SECONDS, default 2), and worker and scheduler report that they are alive in a database table, which /readyz reads. The PostgreSQL connection is therefore the one internal connection that every role needs.

Running the roles on separate hosts is not supported in 0.x. The release stack runs everything on one host: api and worker both mount the restow-data volume, which holds the default local storage, and the same import folder, postgres is reachable only on the Docker network, worker and scheduler offer nothing to connect to, and the updater manages exactly one Compose project. There is no remote worker and no way to point a worker on another machine at an installation. To get more throughput on one installation, give the host more resources and run more worker containers (see Sizing).

An endpoint never talks to the storage target. It talks to your instance, and the instance writes to the storage:

  1. The agent opens HTTPS connections to port 443 of the address of your instance (the public URL), for its regular contact on /agent/v1/... and for the backup data.
  2. During a backup, restic on the endpoint uses the REST backend protocol against rest:https://<instance>/agent/restic/<endpoint id>/, authenticated with HTTP Basic (endpoint ID and agent secret). Caddy passes /agent/restic/* to api:3000 and streams it in both directions, with no body size limit at the edge.
  3. The api implements restic’s REST protocol itself, with no separate repository server. It checks the credentials, applies the append-only rules and the storage budget, and reads and writes the objects through the storage layer of the tenant: they land in the tenant’s primary target under endpoints/<endpoint id>/. A local volume, an S3 bucket and a mounted NFS path take the same code path.
  4. The agent never receives storage credentials: no S3 keys, no mount paths, no direct connection to the storage. It also accepts a repository only on the host of your instance and refuses any other.
  5. Retention, repository checks, restore tests, browsing and downloads are done by the server, as restic processes in the worker or api container. They use a listener on 127.0.0.1 of that container that lives for one operation, so there is no maintenance access from the network.

For the firewall this means:

  • Endpoints need outbound HTTPS to your instance only, and a name that resolves. Behind a proxy they honor HTTPS_PROXY and NO_PROXY; a private certificate authority needs SSL_CERT_FILE or an entry in the trust store (see Proxy and private CA).
  • The storage target needs no inbound connection from endpoints. Only the Restow host connects to it.
  • A reverse proxy in front of Restow must let large bodies through: an agent uploads restic packs of up to 128 MiB per object, and the api refuses more. A proxy with a smaller limit answers with 413.

The paths and request size limits are listed in Ports and roles. The security properties are in Security model.

How Proxmox VE nodes reach their repository

Section titled “How Proxmox VE nodes reach their repository”

Backing up VMs and containers of Proxmox VE (a preview, see Proxmox VE backup) works like the agents: the node never talks to the storage target, only to your instance, and only outbound.

  • The helper restow-pve on each node opens HTTPS connections to port 443 of the address of your instance, authenticated with the node’s own secret. Every minute it reports and asks for tasks (/agent/pve/v1/...), and every five minutes it reports the guests of the node. The instance never connects to a node: a task such as “Back up now” reaches the node in the answer to its next report.
  • For VM disks, the node sends changed 4 MiB blocks in frames of up to 16 blocks to /agent/pve/v1/.... The api checks every block’s SHA-256 and writes it through the storage layer of the tenant. The Caddy edge accepts bodies of up to 80 MiB on this path.
  • For containers, restic on the node writes to rest:https://<instance>/agent/pve/restic/<guest id>/ with a credential that is valid for one run and can only add data. The edge streams /agent/pve/restic/* like /agent/restic/*, without a size limit. The data lands in the tenant’s primary target under pve-guests/<guest id>/.
  • The installer and the helper’s updates download from /install/pve.sh and /install/agent/<version>/... of the same instance.
  • On the node itself, the helper talks to the Proxmox VE API on 127.0.0.1:8006. That connection never leaves the node.
  • A node needs outbound HTTPS to your instance only, and a name that resolves. It honors HTTPS_PROXY and NO_PROXY. A reverse proxy in front of Restow must let bodies of at least 128 MiB through, as for the agents.

The paths are listed in Ports and roles.

The api and the worker write and read the storage of every tenant. What they need depends on the target type:

Target Network path Port Notes
Local volume (default) None. The Docker volume restow-data is mounted at /data in api and worker (STORAGE_LOCAL_PATH, default /data/chunks). None It lives on the disk of the Restow host.
S3-compatible api and worker to the endpoint of the service 443 (HTTPS), or the port in the endpoint URL, for example https://s3.example.com:9000 Since 0.4.0 the endpoint must use https://: a new or changed endpoint over plain http:// is refused (endpoint_insecure), except to localhost, 127.0.0.1 and [::1]. Endpoints saved before keep working and are marked in red. Test setups set S3_ALLOW_INSECURE=true.
NFS The share is mounted on the Docker host, and the mounted folder is passed into api and worker as a path. Restow sees a directory and does not speak NFS itself. SMB is not a supported storage mount since 0.2.1; a path mounted earlier keeps working. NFS: TCP 2049. From the host to the NAS. NFSv4 needs only port 2049; older NFSv3 also needs the portmapper and further ports. The release Compose file contains no such mount. Since 0.3.1 the mounter adds it from the web interface (see Mounter and NFS storage); without it you add the mount yourself, for example with a Compose override. The NAS must allow the address of the Restow host.
Copy targets The same paths, once per target Per target type Every new backup also goes to the copy targets. See Backups and schedules.

The standalone restore tool restow-restore reads a storage folder directly and needs no Restow server, no database and no connection to Restow. It takes a path, so for S3 you mount or copy the bucket first. See Backing up Restow itself.

File share backup (since 0.4.0, see File shares) reads SMB shares and NFS exports of your file servers without an agent on them. The connection is made by the Docker host, not by a container: the mounter creates a short-lived Docker volume of the local driver, the kernel of the host mounts the share through it, and a runner container sees only the mounted folder, read-only for a backup.

Protocol Port, from the Docker host to the file server Notes
SMB TCP 445 SMB 2.1 to 3.1.1. SMB1 and NTLMv1 are refused. Needs the cifs module in the host’s kernel.
NFS TCP 2049 NFSv4 needs only this port. NFSv3 also needs the portmapper (111) and the mount daemon. Needs the NFS client on the host (nfs-common, nfs-utils). The export must allow the address of the Docker host.
  • Nothing is opened inbound. The file server needs no connection to Restow, and the runners have no network of their own besides the internal runners network to the api.
  • Name and address. The file server’s name must resolve on the Docker host. Restow judges the address on every test and run: a server on a private or loopback address needs a provider administrator’s approval or the installation switch Tenants may add file shares in private networks (Installation → Default repository & network shares → File share runners) for a tenant administrator (see Budgets, networks and runners).
  • Through a VPN or routing. The file server must be reachable from the Docker host itself. A customer’s file server behind a site-to-site VPN works when the Docker host routes there. A slow link is used as it is: Restow backs up over it.
  • SELinux. On a host with SELinux enforcing, set RESTOW_MOUNTER_SELINUX_CONTEXT=true in the environment of the mounter service; a line in .env does not reach it (see File shares: the Docker host).

Pick the scenario that matches how you reach the host. Each one has its own rule set.

This is the usual layout for a provider who runs one Restow installation on its own VM at a hosting provider such as Hetzner Cloud or in Azure. The VM has a public address, the DNS record of RESTOW_APP_DOMAIN points at it, and Caddy gets its certificate from Let’s Encrypt (for example installed with --domain restow.example.com, see Get started). The cloud firewall of the provider does the filtering.

Inbound rules at the cloud firewall:

Protocol Port Source Purpose
TCP 443 Anywhere (0.0.0.0/0 and ::/0) Web interface, agents, install scripts, TLS-ALPN validation
TCP 80 Anywhere Let’s Encrypt HTTP validation, redirect to HTTPS
TCP 25 Anywhere Exchange journaling and forwarded copies only; leave it out otherwise
TCP 22 Your administrator addresses SSH

Everything else stays closed. Outbound traffic can stay open, which is the default at both providers apart from port 25 (below), or you restrict it to the outbound table.

Example: Restow on a dedicated VM with a public addressBrowsers, agents, Let's Encrypt, Exchange Online and an administrator workstation connect from the internet through the cloud firewall (Hetzner Cloud Firewall or Azure network security group) to the Restow VM at 203.0.113.50: HTTPS on 443, Let's Encrypt validation on 80 and 443, journaling on 25 and SSH on 22 from admin addresses only. From the VM, connections go out to Microsoft 365, S3 storage and update sources on 443 and to a mail relay on 587.InternetRestow VMInternetBrowsers and agentsany addressLet's Encryptcertificate checksExchange OnlinejournalingAdmin workstationadmin IPs onlyDocker host203.0.113.50Caddy: 80, 443api: journal receiver 25worker, scheduler, postgresno other published portMicrosoft 365Graph, sign-inS3 storageS3-compatibleUpdatesghcr.io, GitHubMail relaynotificationsCloudfirewallHetzner CloudFirewall orAzure NSGHTTPS443validation80/443SMTP25SSH22HTTPS443HTTPS443HTTPS443SMTP587Connection: the dot is the side that opens itOptional feature443Port
Example for a dedicated VM at a hosting provider. The cloud firewall sits outside the VM, so Docker cannot bypass it.

What the two providers do on their side:

Topic Hetzner Cloud Azure
Filtering A Cloud Firewall blocks all inbound traffic that no rule allows and permits all outbound traffic, until you add outbound rules (then only the listed addresses are allowed). A server without a firewall has no filtering. A network security group on the network interface or subnet. The default rule DenyAllInbound (priority 65500) blocks inbound traffic that no rule allows; add yours with a lower priority number. A Standard SKU public IP is closed to inbound traffic until a group allows it. AllowInternetOutBound allows outbound traffic.
Outbound TCP 25 Blocked by default on all cloud servers, together with 465. After a month with a paid invoice you can ask for an exception with a limit request, decided case by case. The block is enforced per account. (FAQ) Blocked on pay-as-you-go, MSDN, Azure Pass, Azure in Open, Education and Free trial subscriptions and on Cloud Solution Provider (CSP) subscriptions, with no way to lift it. Enterprise Dev/Test blocks it by default, and an exemption is possible. Not blocked on Enterprise Agreement and MCA-E. (Microsoft)
Outbound TCP 587 Not blocked Not blocked, whatever the subscription type
Inbound TCP 25 The FAQ describes the block for sending mail and names no inbound restriction. Test it from outside. The article describes the block for outbound connections only; inbound traffic is decided by your security group. Test it from outside.

What this means for Restow:

  • Notification mail must not use port 25 on these platforms. Use an authenticated relay on 587 (STARTTLS) or 465 if the provider lets it through, or use Microsoft Graph sendMail, which Restow supports and which travels over port 443 (see Setup wizard). Microsoft recommends an authenticated relay on 587 for mail from Azure VMs too.
  • Exchange journaling and forwarded copies need only the inbound side: the journal receiver receives and never sends. Port 25 inbound at the cloud firewall is enough. The receiver needs a publicly trusted certificate for the journal host name (see Exchange journaling).
  • Reverse DNS. Restow’s journal setup asks for a host name with an A, AAAA or MX record and a matching certificate, and nothing else. A PTR record matters for mail you send yourself, not for the journal receiver.
  • A fixed address. The DNS records and the Exchange connector point at the address of the VM. In Azure use a Standard SKU public IP, which is static, so that stopping the VM does not change it.

Scenario B: behind an existing reverse proxy in a LAN

Section titled “Scenario B: behind an existing reverse proxy in a LAN”

Use this when a reverse proxy, for example Nginx Proxy Manager, Traefik, HAProxy or a firewall with a proxy plugin such as OPNsense or Sophos, already owns ports 80 and 443 of your public address and hands requests to hosts in the LAN. The public certificate lives on the proxy; Restow sits behind it. The setup steps, with settings for Nginx Proxy Manager, Caddy and Traefik, are in Get started; this page covers the network side.

  • The proxy ends the public TLS. Browsers and agents connect to the proxy with your public domain, for example restow.example.com. Set RESTOW_PUBLIC_URL to that origin; passkeys then work as in any public installation.
  • The hop from the proxy to Restow is encrypted by default. From 0.2.0, the install script’s --behind-proxy sets RESTOW_EDGE_TLS=internal. Caddy then serves port 443 with certificates from its own internal certificate authority instead of asking Let’s Encrypt, so the Restow host needs no public DNS record and no port 80 (the script publishes it on the loopback only). The proxy forwards to https://<Restow host>:443 and sends the public domain as server name (SNI). From 0.2.0 the script copies the root certificate of that authority to /opt/restow/edge-root-ca.crt, so that the proxy can verify the connection; nothing requires that. The same file is /data/caddy/pki/authorities/local/root.crt in the caddy-data volume; docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt ./edge-root-ca.crt copies it out.
  • A plain HTTP hop is an exception. --proxy-hop http (on 0.1.0 the setup by hand) makes the proxy talk plain HTTP to port 80 of the Restow host, which is then open to every machine that can reach it, while port 443 is published on the loopback only. Use it only when the proxy and Restow run on one host or in an isolated network: passwords, session cookies, agent secrets and the mail you open or restore then cross the network unencrypted.
  • Name the proxy in RESTOW_EDGE_TRUSTED_PROXIES: the address of the proxy itself, for example 192.168.10.20/32, not your whole network. Every listed address may claim any client address, so a range or private_ranges would let any machine in it pretend to be someone else in the audit log and slip past the sign-in rate limit. Caddy and the api then take the client address from X-Forwarded-For, which the audit log, the operator notice acceptance, the sign-in rate limit and the agent lockout use. From 0.2.0 the install script’s --proxy-ip sets it. Without it every client appears with the address of the proxy.
  • Port 25 cannot go through an HTTP proxy. Exchange Online (and a provider that forwards copies) delivers to port 25 with SMTP and STARTTLS, which an HTTP proxy does not speak. Forward TCP 25 of the public address by NAT (a port forward on the router or firewall) straight to the Restow host. Do not rewrite the source address, because the receiver limits the rate per sender address and would count all senders as one. The certificate of the journal host name lives on the Restow host, not on the proxy: Caddy holds no certificate for it (and with RESTOW_EDGE_TLS=internal no public one at all), so issue it with another ACME client using the DNS challenge, as described in Exchange journaling.
  • Agents inside the LAN use the same public name. An agent accepts a repository only on the host of the public URL, so there is no separate internal name for it. From inside the LAN the name must lead to the proxy: either split DNS (your LAN resolver answers restow.example.com with the address of the proxy) or hairpin NAT, also called NAT loopback or reflection (the router sends a connection from the LAN to the public address back to the proxy). Split DNS is the cleaner choice. Either way the agent sees the public certificate of the proxy. Agents outside the LAN reach the public address, the router forwards port 443 to the proxy.

What the proxy has to do:

Setting Value Why
Upstream From 0.2.0, the default: https://<Restow host>:443. With --proxy-hop http: http://<Restow host>:80. The edge serves Restow on these ports. api:3000 is not published and is not an upstream.
Host header The public domain, unchanged Caddy serves the site of RESTOW_APP_DOMAIN only.
Graph notifications Pass /api/v1/hooks/graph/ (the two paths for archive capture, since 0.4.4) through like the rest of the site: POST, no sign-in in front, no filter that excludes Microsoft Microsoft Graph calls these paths from the internet. Without them, Restow checks the mailboxes at intervals (Microsoft calls the instance).
Server name (SNI) The public domain. In nginx: proxy_ssl_server_name on; together with proxy_ssl_name restow.example.com; (or proxy_ssl_name $host;) By default nginx takes the name from the upstream address and sends no SNI for an IP address; proxy_ssl_name sets the name that is sent and checked. Caddy answers a connection without SNI with the certificate of RESTOW_APP_DOMAIN. (nginx)
Verification Optional: proxy_ssl_verify on; and proxy_ssl_trusted_certificate with the exported root certificate Without it the hop is encrypted but the proxy does not check who answers.
Client address X-Forwarded-For, which most proxies add Needed together with RESTOW_EDGE_TRUSTED_PROXIES.
Request size At least 128 MiB. In nginx: client_max_body_size 128m; Agents upload packs of up to 128 MiB per object. The nginx default is 1m and answers 413. (nginx)
Timeouts Long enough for large downloads. nginx’s proxy_read_timeout is 60 seconds by default. A large ZIP download breaks off when a proxy cuts an idle connection (see Endpoint backup troubleshooting).
Streaming Do not buffer responses. In nginx: proxy_buffering off; The progress of jobs reaches the browser as a server-sent event stream, which nginx holds back while it buffers responses. Restow opens no WebSocket; a proxy option for WebSocket upgrades can stay on, it does no harm.

Firewall rule sets for the example network in the next section:

Where Direction Rule
Router or firewall WAN to LAN TCP 443 to the proxy
WAN to LAN TCP 80 to the proxy, only if the proxy gets its certificate with the HTTP challenge (with the DNS challenge no inbound port is needed, see Let’s Encrypt)
WAN to LAN TCP 25 to the Restow host, only for journaling, without rewriting the source address
Proxy host Inbound TCP 80 and 443 from the router
Outbound TCP 443 to the Restow host (TCP 80 with --proxy-hop http), and to Let’s Encrypt
Restow host Inbound TCP 443 from the proxy only (TCP 80 with --proxy-hop http); TCP 25 for journaling; TCP 22 from your administrator workstation
Outbound The outbound table, NFS to the NAS and, for file share backup, SMB (TCP 445) or NFS (TCP 2049) to the file servers
NAS Inbound TCP 2049 (NFS) from the Restow host only
File server (file shares) Inbound TCP 445 (SMB) or TCP 2049 (NFS) from the Restow host only

Docker ignores ufw and firewalld rules for published ports, so “from the proxy only” on the Restow host needs RESTOW_HTTPS_PORT bound to one address or a rule in the DOCKER-USER chain; see Get started → Firewall.

Scenario C: LAN only, without a public domain

Section titled “Scenario C: LAN only, without a public domain”

This is local mode. The install script’s --local serves https://localhost or an internal name such as restow.internal with a certificate from Caddy’s own authority; browsers warn about it. The install script describes --local as an evaluation mode, not for production; the network facts below hold for any installation that is reachable from the LAN only.

  • Backup of Microsoft 365 and IMAP works. Both are outbound connections from the Restow host. Microsoft 365 consent returns the administrator’s browser to the redirect URI of the app registration; Microsoft itself does not connect to your server for backup (see First steps).
  • Exchange journaling and forwarded copies are not possible. They need a publicly reachable port 25 and a certificate from a public authority for a public host name.
  • Graph capture polls. Microsoft cannot reach a LAN-only installation, so archiving Microsoft 365 mailboxes by Graph (since 0.4.4) checks each mailbox every 15 minutes instead of being notified. The Archive page says so. IMAP archiving works, because it is outbound.
  • Passkeys are not offered. They need a proper domain with a valid HTTPS certificate (passkey_ready); sign-in uses the emergency password with an authenticator app. See Setup wizard.
  • Agents must be in the LAN or reach it by VPN. They must trust Caddy’s local authority, whose root certificate is /data/caddy/pki/authorities/local/root.crt in the caddy-data volume: add it to the operating system’s trust store, or on Linux point SSL_CERT_FILE at it (see Proxy and private CA).
  • IMAP servers in the LAN are refused by default, see the outbound table.

Rule set of the Restow host:

Direction Rule
Inbound TCP 443 from the LAN, TCP 22 from your administrator workstation. Nothing from the internet.
Outbound The outbound table for the features you use, for example 443 to Microsoft 365

The example for scenario B uses a router with the public address 203.0.113.10 and the LAN 192.168.10.0/24. The addresses are documentation examples (RFC 5737 and a private range); replace them with yours.

Example network: Restow behind a reverse proxy in a LANA site with the public address 203.0.113.10 and the LAN 192.168.10.0/24. The router forwards TCP 443 to the reverse proxy at 192.168.10.20, TCP 80 to the proxy only for its certificate, and TCP 25 directly to the Restow VM at 192.168.10.30 for Exchange journaling. The proxy forwards to the Restow VM over HTTPS on port 443 with the public domain as server name. A remote laptop and a laptop in the LAN, both with the agent, reach Restow through the proxy. The Restow VM mounts a NAS at 192.168.10.40 over NFS 2049 and connects out to cloud services on 443.InternetLAN 192.168.10.0/24Remote laptop198.51.100.23, agentLet's Encryptproxy certificateExchange OnlinejournalingCloud servicesMicrosoft 365, S3, GitHub,ghcr.io, mail relayReverse proxy192.168.10.20public TLS ends here (80, 443)forwards to 192.168.10.30:443server name restow.example.comRestow VM192.168.10.30Caddy 443 (internal CA)api, worker, scheduler, postgresjournal receiver 25DNSrestow.example.compublic: 203.0.113.10LAN: 192.168.10.20archive.example.compublic: 203.0.113.10LAN laptop192.168.10.101, agentuses the LAN DNS answerNAS192.168.10.40NFS 2049Router / firewallWAN 203.0.113.10, LAN 192.168.10.1Port forwardsHTTPS443HTTPS443HTTP80HTTP80ACME443ACME443SMTP25SMTP25not through the proxyHTTPS443HTTPS443HTTPS443NFS2049HTTPS443443 → 192.168.10.2080 → 192.168.10.2025 → 192.168.10.30Connection: the dot is the side that opens itOptional feature443Port
Example for an installation behind a reverse proxy. Addresses are documentation examples (RFC 5737 and a private LAN). The tables below list the same rules.
Device Address Role
Router and firewall 203.0.113.10 (WAN), 192.168.10.1 (LAN) Forwards 443 and 80 to the proxy and 25 to the Restow VM; NAT for outbound traffic
Reverse proxy 192.168.10.20 Holds the public certificate of restow.example.com; forwards to https://192.168.10.30:443 with that server name
Restow VM 192.168.10.30 Docker host with the Restow stack; Caddy on 443 with its internal authority; journal receiver on 25
NAS 192.168.10.40 NFS share for the storage target
LAN laptop 192.168.10.101 Agent; the LAN DNS answers restow.example.com with 192.168.10.20
Remote laptop 198.51.100.23 Agent; reaches restow.example.com at 203.0.113.10

DNS: restow.example.com points to 203.0.113.10 in public DNS and to 192.168.10.20 in the LAN resolver (split DNS). The journal host name archive.example.com points to 203.0.113.10 and is forwarded to 192.168.10.30 on port 25.

Follow two connections through the example. A remote laptop opens HTTPS to restow.example.com, which resolves to 203.0.113.10. The router forwards port 443 to the proxy, the proxy ends the public TLS and opens a new HTTPS connection to 192.168.10.30:443 with the server name restow.example.com, and Caddy passes the request to the api. Exchange Online opens SMTP to archive.example.com:25. The router forwards it straight to 192.168.10.30:25, where the journal receiver in the api container answers with STARTTLS. Neither connection touches the other’s path.

For scenario A the same drawing is shorter, because the VM itself faces the internet and the cloud firewall replaces the router and the proxy (see the drawing in Scenario A). Its public address 203.0.113.50 is also a documentation example.

If you use Open inbound Allow outbound
The web interface TCP 443, and TCP 80 while Caddy gets its own certificate None
Agents on servers and clients The same 443. Nothing on the endpoints. The endpoints need HTTPS to your instance only (HTTPS_PROXY if they sit behind a proxy)
Proxmox VE nodes (VMs and containers, preview) The same 443. Nothing on the nodes. Every node needs HTTPS to your instance only (HTTPS_PROXY if it sits behind a proxy). The helper reaches the Proxmox VE API on 127.0.0.1:8006 on the node itself.
Exchange journaling, forwarded copies from a mail provider (since 0.4.4) TCP 25 straight to the receiver, never through an HTTP proxy, and a certificate for the journal host name None, the receiver never sends
Archive capture of Microsoft 365 mailboxes by Graph (since 0.4.4) The same 443, reachable from Microsoft, with the two paths /api/v1/hooks/graph/ passed through. Optional: without it Restow checks every mailbox every 15 minutes. 443 to login.microsoftonline.com and graph.microsoft.com
IMAP archiving (since 0.4.4) None 993 or 143 to your IMAP servers, one connection per account kept open with IDLE
Notification mail None 587 or 465 to your relay, or Microsoft Graph sendMail over 443
Microsoft 365 backup None 443 to login.microsoftonline.com, graph.microsoft.com and *.sharepoint.com
IMAP backup None 993 or 143 to your IMAP servers
S3 storage None 443, or the port in the endpoint URL, to the S3 service
NFS storage None (the NAS must allow the Restow host) From the host to the NAS: 2049 (NFS)
File share backup (SMB and NFS, since 0.4.0) None (the file server must allow the Restow host) From the Docker host to the file server: 445 (SMB), 2049 (NFS); NFSv3 also 111 and the mount daemon
Local volume only None None
Webhooks None The port in the URL of each target
Update check and updater None 443 to api.github.com, ghcr.io and tuf-repo-cdn.sigstore.dev
Installation and manual updates None 443 to github.com, ghcr.io, registry-1.docker.io, tuf-repo-cdn.sigstore.dev (and download.docker.com)
  • 502 at the proxy. The proxy reaches the host but gets no valid answer from the upstream. Check scheme and port: https on 443 (not http on 443, and not 3000, which is not published), or http on 80 with --proxy-hop http. A TLS error towards the upstream, such as an unknown certificate or a wrong server name, also ends in 502. Test from the proxy host: curl -sk --resolve restow.example.com:443:192.168.10.30 https://restow.example.com/healthz should answer. When the api is down, Caddy answers page requests with its maintenance page and status 503 (see Updates), so a plain 502 page usually comes from the proxy.
  • Let’s Encrypt fails. Caddy needs RESTOW_APP_DOMAIN to resolve to the host and ports 80 and 443 to reach it from the internet. Look at docker compose logs caddy. Check the router, the provider’s firewall and that nothing else holds the ports. Do not restrict port 80 to a list of sources, because Let’s Encrypt validates from several places. Behind a reverse proxy that holds the certificate the Restow host needs none from Let’s Encrypt at all (from 0.2.0 with RESTOW_EDGE_TLS=internal, or with a plain HTTP hop). See Troubleshooting.
  • Archive capture by Graph checks at intervals although it should be notified. The Archive page names the reason. graph.notification_url_unavailable: the public URL is not https:// on 443, or names localhost, a private address or a .local, .internal or .lan host; fix Installation → Server & operation → Server or RESTOW_PUBLIC_URL. graph.subscription_failed: Microsoft refused the subscription, usually because it could not reach or validate https://restow.example.com/api/v1/hooks/graph/notifications; test that path from outside, look at the proxy and the certificate, and Restow tries again after an hour. See Connecting sources.
  • Exchange Online cannot reach the journal receiver. Check in this order: DNS of the journal host name points to the public address; TCP 25 is forwarded straight to the Restow host and not to the proxy, and the provider does not filter it; JOURNAL_SMTP_BIND=0.0.0.0; the certificate matches the journal host name. From outside, openssl s_client -starttls smtp -connect archive.example.com:25 -servername archive.example.com must show the certificate. See Exchange journaling.
  • An agent cannot enroll or back up. From the endpoint, curl -fsS https://restow.example.com/healthz must answer. A private certificate authority needs SSL_CERT_FILE or a trust store entry, a proxy needs HTTPS_PROXY. See Endpoint backup troubleshooting.
  • A Proxmox VE node cannot enroll or back up. From the node, curl -fsS https://restow.example.com/healthz must answer. A proxy needs HTTPS_PROXY. See Troubleshooting Proxmox VE backup.
  • 413 when agents or Proxmox VE nodes upload. A proxy in front of Restow limits the body. Raise it to at least 128 MiB.
  • The audit log shows the proxy as client address. The proxy is missing in RESTOW_EDGE_TRUSTED_PROXIES.
  • A file share test or run fails with share.unreachable. The Docker host gets no answer from the file server: check the name, routing or VPN from the host itself, and that TCP 445 or 2049 is open from the Restow host. See File shares: troubleshooting.
  • A published port ignores your ufw rule. Docker bypasses it, see Scenario A. Filter at the cloud firewall.
  • Notification mail from a cloud VM fails. Port 25 is blocked at Hetzner and Azure by default. Use 587 or Microsoft Graph sendMail.