AMP

Serve AMP using signed exchanges

AMP provides speed benefits above and beyond the format through techniques like caching and preloading. These benefits can have downsides like extra URLs being displayed when embeded inside an AMP Viewer. By serving AMP content using signed exchanges, you can use a new web platform feature to overcome all of these.

A signed exchange is made up of a valid AMP document and the original URL of the content. This information is protected by digital signatures that securely tie the document to its claimed URL. This enables browsers to safely display the original URL in the URL bar instead of the hostname of the machine that delivered the bytes to the browser.

Signed AMP content is delivered in addition to (rather than instead of) regular AMP content.

This feature is currently supported on Chrome, but implementation is planned for additional browsers.

Will signed exchanges work for me?

To implement signed exchanges, you must meet the following requirements:

  • Ability to configure and control the HTTP headers generated by your server. (Most purely web-based hosting solutions such as Blogger are not compatible with signed exchanges.)
  • The ability to generate AMP signed exchanges, such as by running amppackager, as a Go binary, or within a Docker VM.
  • The packager needs to be updated every six weeks.
  • The ability to Vary on Accept and AMP-Cache-Transform headers on edge HTTP servers, returning different content for the same URL.
  • The system running the amppackager needs to be able to make outgoing network requests to:
  • The certificate authority that issues your certificate
  • The publisher server that hosts the AMP documents to sign
  • cdn.ampproject.org to obtain the current version of AMP
  • A persistent shared storage filesystem between all instances of amppackager running in the same data center.

Implementing signed exchanges

Below is the suggested order of implementation to support signed exchanges on your AMP documents.

Acquire a supported TLS certificate

To produce signed exchanges, you need a TLS certificate with the CanSignHttpExchanges extension. As of April 2019, DigiCert is the only provider of this extension (more info).

In order to generate the certificate, the Certificate Authority (CA) will require a Certificate Signing Request (CSR), which can be generated by openssl. An example CSR for ampbyexample.com:

# generate private key (if necessary)
$ openssl ecparam -out ampbyexample-packager.key -name prime256v1 -genkey
# generate CSR (the file ampbyexample-packager.csr)
$ openssl req -new -key ampbyexample-packager.key -nodes -out ampbyexample-packager.csr -subj "/C=US/ST=California/L=Mountain View/O=Google LLC/CN=ampbyexample.com"

Determine which URLs will be signed

You will need to create a URL pattern that defines which documents should be signed. It is critical that private content, such as personalized information should not be signed, to avoid sending misleading or incorrect content.

For performance purposes, the packager should only be passed valid AMP documents as input. Some invalid AMP documents are fine if needed, but you should avoid sending all traffic through the packager.

Deploy packager to a staging server

You should first set up signed exchanges on a staging server to verify your setup is correct before migrating to production.

We recommend using amppackager to generate signed exchanges. However if this is not a good fit for your production environment you can instead use the command-line clients transform and gen-signedexchange, and handle the content negotiation and certificate management tasks yourself.

The following instructions apply to the deployments using amppackager.

Configuration

amppackager's config file (amppkg.toml) calls for a CertFile and a KeyFile.

The KeyFile is the private key (ampbyexample-packager.key in the example above), and it should have the following format. (Note: do not share your own private key, and protect it from inadvertent sharing!)

-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINDgf1gprbdD6hM1ttmRC9+tOqJ+lNRtHwZahJIXfLADoAoGCCqGSM49

4j1NY29jVmAMQYrBYb+6heiv6ok+8c/zJQ==
-----END EC PRIVATE KEY-----

The CertFile is the public certificate. If DigiCert provided the certificate, this can be created by concatenating together the origin-specific certificate provided by DigiCert and the DigiCertCA.crt file.

-----BEGIN CERTIFICATE-----
MIIE0zCCBFmgAwIBAgIQCkEgeFknZluZtdcJnvdFCjAKBggqhkjOPQQDAjBMMQsw
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSYwJAYDVQQDEx1EaWdp
Q2VydCBFQ0MgU2VjdXJlIFNlcnZlciBDQTAeFw0xODEwMzAwMDAwMDBaFw0xOTEx
MDYxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJjYTEWMBQGA1UEBxMN
TW91bnRhaW4gVmlldzETMBEGA1UEChMKR29vZ2xlIExMQzEZMBcGA1UEAxMQYW1w
YnlleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAGu0CjzWa6i

PXLGRK8i0lr7Jv6ZKPY8tfaB/c5yK404QU4HNggmAiEAlnNjIerjJOLHb8CvVaUQ
nhhn0a35nHp1yvE651W14fMwCgYIKoZIzj0EAwIDaAAwZQIwI4/7dpqJQxkQwpP3
DAjVOFdjC6PDcUIRPll3bF0srrTUXSyZ8xkM4q/RhB51A0hVAjEAsUGNYBje9RIO
wf9qyV2iHB+9cBwgKfC0KvEcBugbgHShypM8hPhV9UMC3qTpdKPx
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT

loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd
Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc=
-----END CERTIFICATE-----

Installation

Follow instructions here to set up amppackager for your site.

See packager.js (used by amp.dev) for an example of the server-side changes you will need to make to route the required requests to amppkg.

Testing

Verify that your staging site responds with content of MIME type application/signed-exchange when specified by the HTTP request. For example (replace staging.example.com with your staging server):

$ curl -si -H 'amp-cache-transform: google;v="1..100"' -H 'accept: application/signed-exchange;v=b3;q=0.9,*/*;q=0.8' https://staging.example.com/ | less

The output must include this line:

content-type: application/signed-exchange;v=b3

The v="1..100" in the request is a placeholder. Do not match on this exact value; instead, as described in the amppackager installation instructions, check for the existence of the amp-cache-transform header only, and ignore the value.

The v=b3 version string in the response is the version as of August 2019. This version will change.

The bulk of the response should be your AMP page (in plaintext). There's a small binary header, and, if the page is >16kb, a few binary bytes sprinkled throughout.

The dump-signedexchange tool can be used to inspect the response:

$ curl -s --output - -H 'amp-cache-transform: google;v="1..100"' -H 'accept: application/signed-exchange;v=b3;q=0.9,*/*;q=0.8' https://staging.example.com/ > example.sxg
$ dump-signedexchange -i example.sxg
format version: 1b3

(Note that the -verify switch will not work at this point because the required certificates are not on the https://example.com/ server.)

Verify that the response always include the Vary header with the value Accept,AMP-Cache-Transform (irrespective of whether the MIME type is text/html, application/signed-exchange, or something else):

$ curl -si https://staging.example.com/ | less

This output must include this line:

vary: Accept,AMP-Cache-Transform

Deploy packager to production

Installation

Adjust the staging deployment steps above as appropriate for your production environment.

Testing

With command-line tools

Run through the same tests as above. dump-signedexchange -verify should now also succeed.

With Chrome

You can also test in Chrome with the help of the ModHeader extension. Install it from the Chrome Webstore and configure the Request Headers to amp-cache-transform with a Value of google.

After requesting https://example.com/ your server will deliver a signed exchange, but it should look and behave the same as before. You will need to check that a signed exchange is correctly being returned via the DevTools console.

Under the Network tab, click on your domain name and check that Signed HTTP exchange appears under Preview.

With the Google AMP Cache

Confirm that the signed exchanges are compatible with the Google AMP cache. This related to their discoverability on search engines such as Google Search.

To test signed exchanges in the Google AMP cache, open the network tab in DevTools, enable Preserve log, and visit a URL such as https://example-com.cdn.ampproject.org/wp/s/example.com/.

DevTools will show a 200 with a signed-exchange row, and a from signed-exchange row, if the request was successful.

If unsuccessful, the signed-exchange rows will be missing, or they will be highlighted red. A warning header may also be present that provides additional information.

If your AMP pages were successfully distributed as signed exchanges, their search results will display the AMP lightning bolt, same as before, but tapping on the results will show https://example.com in the URL bar, instead of a URL beginning with https://www.google.com/amp/….. Additionally, the viewer bar will not appear.

Within the DevTools console, under the network tab, you will be able to see signed-exchange under the type column.

Signed exchange service providers

Here is a list of CDNs and hosting providers offering out-of-the-box support for signed exchanges. Using one of these is the easiest way to get started with signed exchanges: