How to generate a TLS certificate with SXG extensions, install tools for generating SXG files, and configure nginx to serve SXG files.
Signed HTTP Exchanges (SXG) is a new web technology that makes it easier for users to tell content creators apart from content distributors. This guide shows you how to set up SXG.
Cross-browser support
Several Chromium-based browsers support SXG, including Google Chrome, Samsung Internet, and Microsoft Edge. See the Consensus and Standardization section of Origin-Signed HTTP Exchanges for more up-to-date information.
Prerequisites
To implement SXG on your website, you must:
- Have control over your domain, including DNS entries.
- Get certificates. SXG requires the issuance of a dedicated certificate. In particular, you cannot reuse your TLS key or certificate.
- Have an HTTP server that can generate and serve SXG over HTTPS.
Assumptions
This guide assumes that you:
- Have an OpenSSL 1.1.1 environment. This guide was written with Ubuntu 18.04 LTS on amd64 ISA.
- Have the ability to run
sudo
to install executables. - Use
nginx
as an HTTP server. - Are using DigiCert to generate certificates that include SXG-related extensions, because it currently appears to be the only provider that supports these extensions.
Also, the example commands in this article assume your domain is website.test
, so you'll need to replace website.test
with your actual domain.
Step 1: Get your certificate for SXG
To generate SXG, you need a TLS certificate with the CanSignHttpExchanges
extension, as well as a particular key type.
DigiCert provides certificates with this extension.
You need a CSR file for issuance of a certificate, so generate it with the following commands:
openssl ecparam -genkey -name prime256v1 -out mySxg.key
openssl req -new -key mySxg.key -nodes -out mySxg.csr -subj "/O=Test/C=US/CN=website.test"
You will get a CSR file that looks like the following:
-----BEGIN CERTIFICATE REQUEST-----
MIHuMIGVAgEAMDMxDTALBgNVBAoMBFRlc3QxCzAJBgNVBAYTAlVTMRUwEwYDVQQD
DAx3ZWJzaXRlLnRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS7IVaeMvid
S5UO7BspzSe5eqT5Qk6X6dCggUiV/vyqQaFDjA/ALyTofgXpbCaksorPaDhdA+f9
APdHWkTbbdv1oAAwCgYIKoZIzj0EAwIDSAAwRQIhAIb7n7Kcc6Y6pU3vFr8SDNkB
kEadlVKNA24SVZ/hn3fjAiAS2tWXhYdJX6xjf2+DL/smB36MKbXg7VWy0K1tWmFi
Sg==
-----END CERTIFICATE REQUEST-----
Make sure that:
- The validity period does not exceed 90 days.
- The Include the CanSignHttpExchanges extension in the certificate checkbox is enabled, which is found under Additional Certificate Options.
If your certificate does not match these conditions, browsers and distributors will reject your SXG for security reasons.
This guide assumes that the filename of the certificate you got from DigiCert is mySxg.pem
.
Step 2: Install libsxg
The SXG format is complex and hard to generate without using tools. You can use one of the following options to generate SXG:
- The gen-signedexchange tool written in Go.
- The
libsxg
library written in C.
This guide uses libsxg
.
Option 1: Install libsxg
from a Debian package
You can install the package in the usual Debian way, as long as the OpenSSL (libssl-dev
) version matches.
sudo apt install -y libssl-dev
wget https://github.com/google/libsxg/releases/download/v0.2/libsxg0_0.2-1_amd64.deb
wget https://github.com/google/libsxg/releases/download/v0.2/libsxg-dev_0.2-1_amd64.deb
sudo dpkg -i libsxg0_0.2-1_amd64.deb
sudo dpkg -i libsxg-dev_0.2-1_amd64.deb
Option 2: Build libsxg
manually
If you are not using an environment compatible with .deb
files, you can build libsxg
yourself.
As a precondition, you need to install git
, cmake
, openssl
, and gcc
.
git clone https://github.com/google/libsxg
mkdir libsxg/build
cd libsxg/build
cmake .. -DRUN_TEST=false -DCMAKE_BUILD_TYPE=Release
make
sudo make install
Step 3: Install nginx
plugin
The nginx
plugin allows you to generate SXG dynamically instead of statically generating them prior to serving.
Option 1: Install the plugin from a Debian package
The SXG module for nginx
is distributed on GitHub.
On Debian-based systems, you can install it as a binary package:
sudo apt install -y nginx=1.15.9-0
wget https://github.com/google/nginx-sxg-module/releases/download/v0.1/libnginx-mod-http-sxg-filter_1.15.9-0ubuntu1.1_amd64.deb
sudo dpkg -i libnginx-mod-http-sxg-filter_1.15.9-0ubuntu1.1_amd64.deb
Option 2: Build plugin manually
Building the nginx
module requires the nginx
source code.
You can get the tarball and build it along with the SXG dynamic module using the commands below:
git clone https://github.com/google/nginx-sxg-module
wget https://nginx.org/download/nginx-1.17.5.tar.gz
tar xvf nginx-1.17.5.tar.gz
cd nginx-1.17.5
./configure --prefix=/opt/nginx --add-dynamic-module=../nginx-sxg-module --without-http_rewrite_module --with-http_ssl_module
make
sudo make install
The nginx
configuration has great flexibility.
Install nginx
anywhere in your system, then specify a respective path of module/config/log/pidfile
.
This guide assumes that you install it to /opt/nginx
.
Step 4: Configure the nginx
plugin to work with SXG
Option 1: Configure an installed-from-Debian nginx
module
Follow these instructions if you used Step 3, Option 1 earlier.
Delivering SXG content requires HTTPS. You can get an SSL/TLS certificate from DigiCert, Let's Encrypt, and other services. Note that you CANNOT use an SXG certificate for SSL or vice versa, therefore you will need two certificates. The configuration file in /etc/nginx/nginx.conf
should look similar to the following, assuming that you put the SSL key/certificate pair in /path/to/ssl/
and the SXG key/certificate pair in /path/to/sxg/
:
user www-data;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
include mime.types;
default_type application/octet-stream;
add_header X-Content-Type-Options nosniff;
server {
listen 443 ssl;
ssl_certificate /path/to/ssl/fullchain.pem;
ssl_certificate_key /path/to/ssl/privkey.pem;
server_name website.test;
sxg on;
sxg_certificate /path/to/sxg/mySxg.pem;
sxg_certificate_key /path/to/sxg/mySxg.key;
sxg_cert_url https://website.test/certs/cert.cbor;
sxg_validity_url https://website.test/validity/resource.msg;
sxg_cert_path /certs/cert.cbor;
root /var/www/html;
}
}
sxg_cert_url
is essential for browsers to load SXG properly because it locates the certificate chain. The certificate chain contains certificate and OCSP stapling information with cbor format. Note that you do not have to serve thecert.cbor
file from the same origin. You can serve it via any CDNs or other static file serving services as long as it supports HTTPS.sxg_validitiy_url
is planned to serve SXG-signature-header-related information. If a page has not been modified since the last SXG, downloading the entire SXG file is not required technically. So updating signature header information alone is expected to reduce network traffic. But the details are not implemented yet.
Start nginx
and you are ready to serve SXG!
sudo systemctl start nginx.service
curl -H"Accept: application/signed-exchange;v=b3" https://website.test/ > index.html.sxg
cat index.html.sxg
sxg1-b3...https://website.test/...(omit)
Option 2: Configure a built-from-source nginx
module
Follow these instructions if you used Step 3, Option 2 earlier.
Configure your nginx
system installed under /opt/nginx
to look similar to the following example:
load_module "/opt/nginx/modules/ngx_http_sxg_filter_module.so";
events {
worker_connections 768;
}
http {
include mime.types;
default_type application/octet-stream;
add_header X-Content-Type-Options nosniff;
server {
listen 443 ssl;
ssl_certificate /path/to/ssl/fullchain.pem;
ssl_certificate_key /path/to/ssl/privkey.pem;
server_name example.com;
sxg on;
sxg_certificate /path/to/sxg/mySxg.pem;
sxg_certificate_key /path/to/sxg/mySxg.key;
sxg_cert_url https://website.test/certs/cert.cbor;
sxg_validity_url https://website.test/validity/resource.msg;
sxg_cert_path /certs/cert.cbor;
root /opt/nginx/html;
}
}
Then start nginx
. Now you can get your SXG!
cd /opt/nginx/sbin
sudo ./nginx
curl -H "Accept: application/signed-exchange;v=b3" https://website.test/ > index.html.sxg
less index.html.sxg
sxg1-b3...https://website.test/...(omit)
Step 5: Serve your application backend
In the above examples, nginx
serves static files in the root directory, but you can use upstream directives for your applications to make SXG for arbitrary web application backends (such as Ruby on Rails, Django, or Express) as long as your nginx
works as a front HTTP(S) server.
upstream app {
server 127.0.0.1:8080;
}
server {
location / {
proxy_pass http://app;
}
}
Step 6: Test
Use the dump-signedexchange tool to test that the SXGs being served are correct, ensure that no errors are reported, and verify that the headers and body are as expected.
go get -u github.com/WICG/webpackage/go/signedexchange/cmd/dump-signedexchange
export PATH=$PATH:~/go/bin
dump-signedexchange -verify -uri https://website.test/ | less
Send feedback
The Chromium engineers working on SXG are keen to hear your feedback at webpackage-dev@chromium.org. You can also join the spec discussion, or report a bug to the team. Your feedback will greatly help the standardization process and also help address implementation issues. Thank you!