All documentation
Server operations

Web services

Put a domain in front of something already on the server: a port a process listens on, or a directory you fill yourself.

What a web service is

A web service is a site with no repository, no build, and no release. Provisore writes the Nginx server block for the domain, and you run whatever answers behind it. Create one with New web service on a server's Sites page, where web services have their own table below the sites.

  • Reverse proxy to a port. Nginx terminates TLS and forwards every request to a port on this server.
  • Serve a directory. Nginx serves a directory on this server that you fill yourself.

Both take a primary domain and up to ten aliases, like a site. Both get certificates the same way too. Point DNS at the server, deploy once, then issue one under SSL in the site's Settings. See Domains, DNS & SSL. Neither has a repository, a branch, a deploy script, or a build command, and the API refuses those fields rather than ignoring them.

Reverse proxy to a port

Give the port and Provisore renders a proxy_pass to 127.0.0.1 on it, forwarding Host, X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto. WebSocket upgrades work on every path. The server block passes Upgrade and Connection through over HTTP/1.1, so a socket server behind the port needs no extra configuration.

A reverse proxy web service
Domain    ws.example.com
Serves    Reverse proxy to a port
Port      2096
Daemon    relay

The port must be between 1024 and 65535, outside 30000 to 39999. The privileged ports on a Provisore server are taken: 22 is sshd, and 80 and 443 are the Nginx doing the forwarding. An unprivileged process cannot bind them anyway.

Provisore runs its Swift and Node sites on ports in the excluded band. Each site's port is derived, not allocated from a table you can read. A proxy aimed into that band would not fail. Its domain would answer with another site's application, either now or once the next service site is created on the same server. The form refuses the number as you type it, and the deploy checks it again on the server.

Two web services may name the same port. One backend often serves several hostnames from one listener, and Provisore owns none of these ports.

Naming the daemon behind the port

You can name which of the server's daemons listens on the port. The web service and the daemon then each show the other, so the next person to look sees a process behind the domain rather than a bare port number.

The web service does not own the daemon. Several can name the same one, for one process serving several hostnames. While any of them name it, deleting the daemon fails with 409 daemon_in_use and a list of the domains. Unbinding changes nothing on the server, and the domain still forwards to the same port. Unbind the daemon from each web service, or delete them, and you can remove it.

Serving a directory

Provisore creates the document root and serves what is in it. With no repository and no build, the directory stays empty until you fill it.

/home/provisore/sites/files.example.com/
  public/                             # the document root, yours to fill
  shared/                             # the site's persistent files

The document root sits beside shared/ rather than inside a release, because your files arrive between deploys. A document root that moved on every deploy would empty the site.

A request for a missing file gets a 404. There is no fallback to index.html, which would answer every wrong URL with a 200 and make a half-finished sync look like a working site. Dotfiles are denied except under .well-known, and fingerprinted asset paths are served with a long cache header.

Copying the files in

Copy files over SSH as the provisore deploy user, with your key on the server. See Firewall & SSH access.

Publishing a build
rsync -rltvzO --chmod=D755,F644 --delete ./dist/ provisore@203.0.113.10:/home/provisore/sites/files.example.com/public/
Why not rsync -a

The document root belongs to the site's own Unix account, and an ACL gives the provisore account write access to what is inside it. That lets it add, replace, and delete files, but not change the directory itself. -a implies -p, -o, -g and -t, and setting a directory's mode, owner or modification time needs ownership. Every file transfers correctly and rsync still exits 23, having failed on the destination root. The flags above copy recursively, keep symlinks and file times, and leave directory metadata alone.

CORS

Both kinds of web service can answer with Access-Control-* headers, set under CORS in the site's Settings. A CDN origin needs them. Without them a browser fetches the file and discards it, and reports the failure only in the console of the site that asked. Other sites do not have these settings, because an application sends its own headers.

List the origins that may read the site. An entry is https://example.com, https://*.example.com, http://localhost:5173, or * on its own for any origin. An empty list sends no CORS headers, and every web service starts with an empty list.

A CDN origin serving one site and its subdomains
Origins         https://acme.com
                https://*.acme.com
Methods         GET, HEAD, OPTIONS
Request headers Origin, Content-Type, Accept, Authorization, Range
Read headers    Accept-Ranges, Content-Range

A wildcard covers subdomains and not the apex, the same rule a wildcard certificate follows. https://*.acme.com matches https://www.acme.com and does not match https://acme.com. To allow both, list both, as above. Forge's equivalent setting worked differently. Its one optional label covered the apex and stopped at one level of subdomain.

* cannot be combined with credentials. A browser discards a credentialed response whose Access-Control-Allow-Origin is *, so the API refuses the pair.

Range is in the default request headers for media. A <video> seeking in a cross-origin file sends it, then reads Accept-Ranges and Content-Range from the response. A browser hides those two headers unless the response names them as readable.

Changing one

Under Web service in the site's Settings you can change a proxy's port and daemon, and either kind's health check path. The CORS policy is under CORS. A served directory's location cannot change, because it follows from the domain. Changes take effect on the next deploy, which for a web service re-renders the Nginx server block and reloads Nginx. Nothing is fetched, built, or restarted, and no file in a served directory is touched.

Deleting one removes its Nginx configuration and site directory from the server. You confirm by typing the domain, as with any other site.

A proxy deploy checks that the domain answers

Provisore requests the site through Nginx at the end of a deploy, so a proxy whose upstream is not listening fails the deploy. The rendered configuration stays in place either way, because removing it would replace a 502 with the server's catch-all 404, which tells you less.