Serving Signed Exchanges with Web Packager
A signed exchange (SXG) lets you authenticate a resource's origin independent of how it was delivered. Web Packager provides tooling for generating and serving SXGs. The setup differs depending on whether you're testing locally or preparing for production.
Testing with a self-signed certificate
Self-signed certificates are suitable for demonstration and testing only. Browsers will flag SXGs signed with them outside of test environments, and you should not serve them to crawlers.
Prerequisites
You'll need openssl and Go installed.
Create the certificate
Generate a private key that will be saved to priv.key:
openssl ecparam -out priv.key -name prime256v1 -genkey
Next, create a certificate signing request (CSR). The CSR below is for an organization named Web Packager Demo with common name example.com. The common name must be the fully qualified domain name of the site whose content you'll package. In production this would be a domain you own; for local testing any domain works.
openssl req -new -sha256 -key priv.key -out cert.csr -subj '/O=Web Packager Demo/CN=example.com'
Now create a certificate carrying the CanSignHttpExchanges extension. This command produces cert.pem from the private key and CSR. The -extfile flag associates the certificate with the CanSignHttpExchanges extension via its object identifier (1.3.6.1.4.1.11129.2.1.22) and also declares example.com as a Subject Alternative Name.
openssl x509 -req -days 90 -in cert.csr -signkey priv.key -out cert.pem -extfile <(echo -e "1.3.6.1.4.1.11129.2.1.22 = ASN1:NULL\nsubjectAltName=DNS:example.com")
To inspect the resulting certificate:
openssl x509 -in cert.pem -noout -text
Configure the Web Packager server
Install Web Packager, then build the webpkgserver binary:
git clone https://github.com/google/webpackager.git
cd webpackager/cmd/webpkgserver
go build .
Verify the binary is on your path:
./webpkgserver --help
This should print usage information for webpkgserver. If not, check that your GOPATH is configured correctly.
Edit webpkgserver.toml
Navigate to the webpkgserver directory and copy the example configuration:
cd /path/to/cmd/webpkgserver
cp ./webpkgserver.example.toml ./webpkgserver.toml
Open webpkgserver.toml and apply these edits:
- Change
#AllowTestCert = falsetoAllowTestCert = true. - Update
PEMFile = 'path/to/your.pem'to the path of yourcert.pemfile. Leave the line beginning withTLS.PEMFileunchanged. - Update
KeyFile = 'priv.key'to the path of your private key. Again, theTLS.KeyFileentry is separate. - Change
#CertURLBase = '/webpkg/cert'toCertURLBase = 'data:'. This controls where the SXG certificate is served from, which populates thecert-urlparameter in theSignatureheader. Production deployments would use a URL likeCertURLBase = 'https://mysite.com/', but for local testing a data URL inlines the certificate directly. - Change
Domain = 'example.org'toexample.com, matching the certificate you generated.webpkgserveronly fetches content from the domain named here; otherwise the logs will show the errorURL doesn't match the fetch targets.
If you want to enable subresource preloading, additional options are available:
- Switch
#PreloadCSS = falsetoPreloadCSS = trueand#PreloadJS = falsetoPreloadJS = trueto havewebpkgserverinsert preload directives for stylesheet and script subresources as SXGs. Alternatively, you can addLink: rel="preload"headers and<link rel="preload">tags manually. - By default, existing
<link rel="preload">tags are replaced with equivalents that fetch the content as SXG.webpkgserversets theallowed-alt-sxgandheader-integritydirectives automatically, so authors don't need to write them. To preserve the original non-SXG preloads, setKeepNonSXGPreloads = true. Note that this may disqualify the SXG from the Google SXG cache per the cache requirements.
Start the server and test in Chrome
Launch the server:
./webpkgserver
Successful startup produces log messages similar to:
Listening at 127.0.0.1:8080
Successfully retrieved valid OCSP.
Writing to cache in /private/tmp/webpkg
The cache directory varies by operating system. If something fails, re-check webpkgserver.toml and restart the server after any edits.
Next, launch Chrome with certificate errors for cert.pem ignored:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--user-data-dir=/tmp/udd \
--ignore-certificate-errors-spki-list=`openssl x509 -noout -pubkey -in cert.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64`
Without this flag, DevTools will report Certificate verification error: ERR_CERT_INVALID. You may need to adjust the path to Chrome and to cert.pem. A warning beneath the address bar should appear with the hash string, e.g.: You are using an unsupported command-line flag: --ignore-certificate-errors-spki-list=9uxADcgc6/ho0mJLRMBcOjfBaN21k0sOInoMchr9CMY=. If that hash is missing, the path to the certificate is wrong.
Open the DevTools Network tab and visit:
http://localhost:8080/priv/doc/https://example.com
This requests a SXG for https://example.com through the local webpkgserver instance. /priv/doc/ is the default API endpoint.
The Network tab will list three resources:
- A
signed-exchangeresource: the SXG itself. - A
cert-chain+cborresource: SXG certificates must be in theapplication/cert-chain+cborformat. - A
documentresource: the content delivered via the SXG.
If these are missing, clear the browser cache and reload the URL. The Preview tab shows details on the signed exchange and its signature:
Deploying SXGs with a CanSignHttpExchanges certificate
For production, signed exchanges require a CanSignHttpExchanges certificate. The setup below assumes familiarity with the concepts covered in the self-signed certificate walkthrough.
What you’ll need
- A
CanSignHttpExchangescertificate from one of the approved certificate authorities. - If you don’t have one yet, you can configure
webpkgserverto fetch certificates automatically from your CA. The relevant settings forwebpkgserver.tomlare documented in the project README. - An edge server in front of
webpkgserveris strongly recommended. Without one, you’ll need to setTLS.PEMFileandTLS.KeyFileinwebpkgserver.toml. The server runs over HTTP by default, but SXG certificates must be served over HTTPS to be trusted by browsers. Enabling TLS letswebpkgserverdeliver the certificate directly.
Configuration steps
Build a PEM file by concatenating your site’s SXG certificate with your CA certificate. (PEM is a common container format for multiple certificates.)
Copy the example configuration to a new
webpkgserver.toml:cp ./webpkgserver.example.toml ./webpkgserver.tomlEdit the file:
- Set
PEMFileto the full path of your combined certificate chain. - Set
KeyFileto the corresponding private key. - Set
Domainto your actual site domain. - Optionally, enable automatic certificate renewal every 90 days (45 for Google) by filling in the
[SXG.ACME]section. This only works if you have a DigiCert or Google ACME account.
- Set
Point your edge server at the
webpkgserverinstance. The server handles two request types: SXG content via the/priv/doc/endpoint and the SXG certificate via/webpkg/cert/. Rewriting rules differ slightly between the two; see the edge server guidance in the README.By default, certificates are served at
/webpkg/cert/$CERT_HASH, where$CERT_HASHis derived from your PEM file:shell openssl base64 -in cert.pem -d | openssl dgst -sha256 -binary | base64 | tr /+ _- | tr -d =



