Origin Rules

Introduction

Origin rules forward requests for a few paths of your published site to a server that answers them dynamically. Every other path is still served from your static site. For example, a rule for /wp-json/* sends the REST API requests of your static site to the WordPress it was published from, so forms and plugin endpoints keep working.

A rule sends its path either to this site’s WordPress, which Staatic manages for you, or to a server of your own. The pricing page lists them as Hybrid routing, with the allowance for each plan.

Before you start

  • Origin rules are available for sites hosted on Staatic Cloud.
  • Managing origin rules requires Site Management access. See Team Access for more information about permissions. If a site shows no Origin rules tab although you have this access, contact support.
  • Rules to this site’s WordPress need the always-on add-on.
  • Rules to your own server need an active custom domain on the site.
  • Use the Staatic plugin 1.13.2 or newer to keep the paths of your rules out of publications automatically. With an older plugin you exclude them yourself; see Keeping forwarded paths out of publications.

Adding a rule

  1. Go to app.staatic.com and login with your account details.
  2. Click Account > Sites. Then click on the View Icon next to the relevant site.
  3. Click the Origin rules tab.
  4. Complete any open items in the Before you can add rules list. If one stays open that you cannot complete, contact support.
  5. Click Add rule and fill in the form.

The plugin item always shows Not checked: Staatic cannot see which plugin version you publish with.

A rule has three parts:

  • Path: the path pattern to forward, for example /wp-json/*. See Writing path patterns.
  • Send to: the destination. This is either This site’s WordPress or a server of your own listed under Destinations.
  • Use on: whether the rule applies to the Live site, the Preview site or the Live and preview sites. New rules apply to the live site unless you choose otherwise. Rules to your own server always apply to the live site only.

A site can have up to 10 rules in total.

Following a rule’s status

A new or changed rule shows Updating for a few minutes, then Active. A rule that cannot be applied yet shows Waiting, with the reason below it. Most reasons tell you what happens next.

These reasons need action from you:

Reason shown with Waiting What to do
Waiting for the steps above. Complete the open items in the Before you can add rules list.
Waiting for api.example.com to finish connecting. Finish the connection steps of your server. See Adding your server.
api.example.com needs a new connection check after its hostname changed. Click Manage for the server, then Check connection.
Waiting for an active custom domain on this site. Set up a custom domain.
This site has no preview site to apply this rule to. Change Use on to Live site, or remove the rule.

A rule that can never match, because a rule above it already matches every path it covers, is marked Never reached. Move it up or remove it.

Editing and removing rules

To change a rule, click Edit next to it, change its Path or Use on and click Save changes. The destination of a rule is fixed: to send a path somewhere else, add a new rule and remove the old one.

Rules are checked from top to bottom, and the first matching rule wins. New rules are added at the bottom; move a rule up or down to change the order.

To remove a rule, click Remove and confirm. Until the removal is applied you can still click Undo.

Once a path is no longer forwarded, it is served from your published site again (or your 404 page if nothing is published there).

Forwarding to this site’s WordPress

Every site on Staatic Cloud has its own WordPress, listed under Destinations as This site’s WordPress. Choose it under Send to when you add a rule. Staatic connects and secures it for you.

The first rule takes a little longer, because Staatic connects the WordPress first; the rule shows Waiting until then.

On a WordPress Multisite network, each site of the network has its own rules and forwards to its own address on the shared WordPress. Add rules on every site that needs them.

Requests are rate-limited per visitor; requests over the limit get a 429 response.

Turning on the always-on add-on

A WordPress on Staatic Cloud pauses when it is idle. Rules to this site’s WordPress need it running, so they need the always-on add-on, which keeps it running.

The always-on add-on is available on every Staatic Cloud plan for €9 ($10) per month or €90 ($100) per year per WordPress instance. It is billed with your subscription and covers every site on that instance, for example every site of a WordPress Multisite network.

To turn it on:

  1. On the Origin rules tab, click Turn on next to the always-on item; it shows the price for your plan.
  2. Switch on Always on and click Update Site.

A trial does not include the add-on; choose a plan with Change plan to add it.

If the add-on stops being active for a WordPress, for example after a plan change, your rules to it keep working. Until the add-on is active again they cannot be changed, reordered or restored; you can still remove them.

You can turn the add-on off on the Subscription page or with the site’s Always on switch, but not while origin rules use that WordPress: remove those rules first.

Forwarding to your own server

Rules to your own server forward paths such as /app/* to an application or API that you host yourself, under your site’s custom domain.

Own servers are available on every Staatic Cloud plan. If the Origin rules tab shows no Add your own server button, contact support.

Your plan sets how many you can use per site:

Plan Per site
Cloud Starter and trials 1 path to 1 of your own servers
Cloud Professional Up to 10 paths to up to 3 of your own servers
Cloud Enterprise Agreed with Staatic

These paths count toward the 10 rules per site, and a site can forward to at most 3 destinations, its own WordPress included. If a site uses more than its plan allows after a plan change, its rules keep working but cannot be changed until you remove some or upgrade.

Adding your server

Your server must:

  • serve HTTPS on port 443 with TLS 1.2 and a valid certificate for its hostname;
  • have a hostname that resolves to a public address. IP addresses and Staatic domains cannot be used;
  • start answering within 30 seconds.

To add it:

  1. On the Origin rules tab, click Add your own server under Destinations.
  2. Enter the Hostname, for example api.example.com: just the name, without https://, port or path.
  3. Optionally enter a Path prefix, for example /api. It is added in front of every forwarded path: /wp-json/app on your site becomes /api/wp-json/app on your server. Leave it empty to forward paths unchanged.
  4. Click Add server.
  5. Copy the secret that is shown and configure your server to check it. See Securing your server.
  6. Click I’ve added it, check the connection.
  7. Click Check again when the panel asks for it. The setup is done once the server shows Connected.

To finish an interrupted setup later, click Finish connecting next to the server.

The secret is shown once, only to the user who added the server, and cannot be shown again. If the secret is lost before any rule uses the server, remove the server and add it again. Once rules use the server, contact support.

The connection check requests the root of your server twice, with and without the secret, without following redirects. The request with the secret must succeed with a small response (at most 64 KiB, below 500); the request without the secret must be refused with 401 or 403.

The result is shown next to the server under Destinations:

Result Meaning
Connected Rules to this server can be applied.
Accepts requests without the secret Your server did not refuse the request without the secret with 401 or 403. Configure it to refuse such requests, then check again.
Refused the secret Your server refused the request with the secret. Check the header name and value.
Unreachable The check got no usable answer, for example a connection or certificate error, a response over 64 KiB or a 5xx. The reason is shown below the result.

Securing your server

Every request that Staatic forwards to your server carries the X-Staatic-Origin-Secret header with your secret. Configure your server to accept a request only when this header equals the secret, and to refuse every other request with 401 or 403. Without this check, anyone who knows your server’s hostname can reach it directly. Staatic removes this header from visitor requests, so a visitor cannot send it.

Forwarded requests come from the shared address ranges of Amazon CloudFront, not from fixed addresses, so an IP allowlist cannot replace the secret check.

The Origin rules tab shows these examples with your secret filled in. Otherwise, replace your-secret with your secret.

nginx, in the server or location block that serves the forwarded paths:

if ($http_x_staatic_origin_secret != "your-secret") {
    return 403;
}

Apache (.htaccess):

RewriteEngine On
RewriteCond %{HTTP:X-Staatic-Origin-Secret} !=your-secret
RewriteRule ^ - [F]

PHP, at the start of your application:

<?php
$given = isset($_SERVER['HTTP_X_STAATIC_ORIGIN_SECRET']) ? $_SERVER['HTTP_X_STAATIC_ORIGIN_SECRET'] : '';
if (!hash_equals('your-secret', $given)) {
    http_response_code(403);
    exit;
}

The IP address of the visitor arrives in the X-Staatic-Viewer-Ip header. Do not use CF-Connecting-IP, X-Forwarded-For, X-Real-IP or Forwarded to identify visitors: a visitor can set some of these headers.

Replacing the secret

You can replace the secret of your server at any time. Requests keep working throughout.

  1. Click Manage next to the server, then Replace secret and Create new secret.
  2. Configure your server to accept both the current and the new secret (examples below).
  3. Click I’ve added it, check the connection, and click Check again when asked; switching takes a few minutes.
  4. When the panel asks you to, remove the old secret from your server and check again.

To accept both secrets, replace current-secret and new-secret in one of these examples:

if ($http_x_staatic_origin_secret !~ "^(current-secret|new-secret)$") {
    return 403;
}
RewriteEngine On
RewriteCond %{HTTP:X-Staatic-Origin-Secret} !=current-secret
RewriteCond %{HTTP:X-Staatic-Origin-Secret} !=new-secret
RewriteRule ^ - [F]
<?php
$given = isset($_SERVER['HTTP_X_STAATIC_ORIGIN_SECRET']) ? $_SERVER['HTTP_X_STAATIC_ORIGIN_SECRET'] : '';
if (!hash_equals('current-secret', $given) && !hash_equals('new-secret', $given)) {
    http_response_code(403);
    exit;
}

Changing or removing your server

To change the hostname or path prefix, click Manage next to the server, then Change hostname or path. After a hostname change, rules that use the server pause until the new hostname passes a connection check.

To remove a server, first remove the rules that use it, then remove the server under Manage. Staatic stops forwarding to it and forgets its secret, so you can then remove the secret check from your server.

Writing path patterns

  • A pattern starts with /.
  • * matches any number of characters, including none and including /. ? matches exactly one character.
  • The whole path must match. /api/status does not match /api/status-extra; use /api/status* for both.
  • Matching is case-sensitive and ignores the query string: /wp-json/* also matches /wp-json/wp/v2/posts?per_page=5.
  • A pattern that matches every path, such as /*, cannot be used.
  • Rules to your own server need a fixed first part: /app/* or /app/*.php work, /*/*, /shop* and /*.php do not.

Keeping forwarded paths out of publications

Forwarded paths should not be part of your published site. Staatic passes the patterns of your rules to the Staatic plugin, and plugin 1.13.2 or newer excludes them from publications automatically.

With an older plugin, add the paths to Excluded URLs in the Build Settings yourself. /wp-json/* is excluded by default unless you removed it from the list. /wp-admin/admin-ajax.php is not; add it if you forward it with an older plugin.

Developers can add exclusions from code with the staatic_exclude_urls filter. See URL processing hooks.

Republish after adding rules.

Testing a rule

Once a rule shows Active, request one of its paths on your live site, for example:

curl -i https://www.example.com/wp-json/

The response should come from the destination, for example the JSON index of the WordPress REST API instead of a page of your static site. For a rule that applies to the preview site, use the address of your preview site.

How requests are forwarded

Behavior
Methods GET, HEAD, OPTIONS, PUT, PATCH, POST and DELETE
Protocol Visitors who use http:// are redirected to https:// first
Caching Never cached
Cookies All cookies are forwarded
Query string Forwarded unchanged
Headers All visitor headers except Host, Forwarded, CF-Connecting-IP and True-Client-IP, plus X-Staatic-Viewer-Ip, X-Staatic-Forwarded-Host (the hostname the visitor requested) and X-Staatic-Forwarded-Proto (always https)
Host The destination’s own hostname
Response timeout 30 seconds to start answering, and at most 30 seconds between packets

Limitations

  • Responses with status 403, 404 or 503 from the destination are replaced by your site’s static error page, with the same status. Other responses reach the visitor as the destination sent them. If the destination cannot be reached or times out, visitors get a 502 or 504 error.
  • Because of this, WordPress REST errors such as rest_no_route (404) and rest_forbidden (403), and failed admin-ajax.php nonce checks (403), reach the visitor as an HTML page instead of JSON. Let your own endpoints answer errors with another status, such as 400, 401 or 422.
  • A path prefix can only be added, not removed: a rule for /app/* reaches your server as /app/....
  • Rules match the path only. Requests cannot be forwarded based on their query string, such as /?s= searches.
  • Origin rules are meant for endpoints such as REST routes and form handlers. Forwarding a login page or pages that depend on a WordPress login session does not give a working login on your published site.
  • Sites that publish to your own hosting (self-hosted sites) cannot use origin rules, because Staatic does not serve them.