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.
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
andAMP-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.
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
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.
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.
Signed exchanges in Google Search
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:
- AMP Packager Google Cloud Click-to-Deploy Installer AMP Packager is a tool to improve AMP URLs by serving AMP using Signed Exchanges. Read more in AMP Blog.
- Cloudflare AMP Real URL. Cloudflare is one of the world’s largest networks. Today, businesses, non-profits, bloggers, and anyone with an Internet presence boast faster, more secure websites and apps thanks to Cloudflare.
-
Written by @CrystalOnScript