A Sandstorm app can publish static web content to any domain of the user's choosing. This is useful for content management systems, blogging platforms, and other apps. This guide helps app authors use that feature of the Sandstorm platform.
In Sandstorm, an app can publish static HTML and other files in a way where Sandstorm will serve the content, rather than the app. This saves on compute time and limits attack surface.
You can try it now with this sample app (full source available).
Store static files in
/var/www. Each directory within
should contain a file called
The grain can ask Sandstorm to enable publishing by requesting the
creation of a unique
publicId. Once that's done, the files are
available on a special subdomain of the Sandstorm install. The
subdomain takes the form
Users can also make the content available at any domain. To do
that, they need to configure a CNAME record pointing at the
Sandstorm install; this is how their domain's DNS will resolve to the
Sandstorm server. The user also needs a TXT record; this is how
Sandstorm determines what
publicId this domain corresponds to.
This page explains how to generate a
publicId and how to instruct a
user of your app to configure their DNS appropriately. This a
provisional API; see the note below about how we aim to make this
more usable and more secure.
A helper program you can include, to enable publishing & request a publicId
The simplest way to enable static publishing is to embed a small C++ program with your app. The Sample Static Publishing App includes that C++ code.
To include the C++ code in your app, copy these
into a directory of your app called
If you are using
vagrant-spk, also add the following to the end of your
### Download & compile capnproto and the Sandstorm getPublicId helper. # First, get capnproto from master and install it to # /usr/local/bin. This requires a C++ compiler. We opt for clang # because that's what Sandstorm is typically compiled with. if [ ! -e /usr/local/bin/capnp ] ; then sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -q clang autoconf pkg-config libtool git cd /tmp if [ ! -e capnproto ]; then git clone https://github.com/sandstorm-io/capnproto; fi cd capnproto git checkout master cd c++ autoreconf -i ./configure make -j2 sudo make install fi # Second, compile the small C++ program within # /opt/app/sandstorm-integration. if [ ! -e /opt/app/sandstorm-integration/getPublicId ] ; then pushd /opt/app/sandstorm-integration make fi ### All done.
Now, run the improved
.sandstorm/setup.sh script by doing:
vagrant-spk vm provision
This should result in a
/opt/app/sandstorm-integration/bin/getPublicId binary showing up in
your directory tree. When you run it and provide the current
X-Sandstorm-Session-Id header as a command-line parameter, it will
publicId (and other information, see below).
If you prefer to use your own build system, you can use the above as inspiration. If you prefer to call Sandstorm's RPC directly, keep reading.
Note: At the time of writing, some vagrant-spk stacks crash if you
vagrant-spk vm provision a second time. We're working on fixing
Show DNS instructions to the user
You should make sure the user knows how to configure their domain's CNAME record (to point at the Sandstorm install) and TXT record (to tell Sandstorm which grain the domain points at).
You can find sample text in the Sandstorm sample app with static publishing. The essentials are:
The user can preview their site at the
bin/getPublicIdprogram prints that as line #3 (
linesin 0-indexed programming languages).
The user should set their CNAME value to the host component of the
autoUrl, for example
publicId.sandstorm.example.com. You can calculate this host component of the URL by parsing the
The user should set up a TXT record at
sandstorm-www.example.comcontaining just the
bin/getPublicIdprogram prints that as line 1 (
linesin 0-indexed programming languages).
Using the Sandstorm Cap'n Proto APIs directly
You can access the Sandstorm
HackSessionContext capability directly
if you want more performance or prefer to use the Sandstorm APIs with
Start by obtaining a
is a Cap'n Proto interface. You must obtain
an instance of this capability. The way to do this depends on whether
your app uses
sandstorm-http-bridge (check your
sandstorm-pkgdef.capnp to find out).
If you are using the raw Cap'n Proto API without the HTTP Bridge, then
SessionContext capability you receive as a parameter to the
UiView.newSession() method can be cast to
If you are using
sandstorm-http-bridge, you must open a Cap'n Proto
unix:/tmp/sandstorm-api, which will give you a
getSessionContext() on that capability, using the
ID that sandstorm-http-bridge places in the
header, and cast the result to a
HackSessionContext is a temporary API. As described below,
we intend to replace this with a better API later.
getPublicId() on the context. The first time you call
this, the grain (app instance) is assigned a "public ID", which is a
random string that uniquely identifies the grain, but which differs
from the "private ID" which appears in the grain's URL. The public ID
is not a secret as it grants no authority over the grain, whereas
anyone who knows the private ID has full control over the grain.
The method call returns the grain's public ID as well as the hostname at which the server is hosted.
Then, instruct the user on how to set up DNS.
The user will need to set two DNS records:
<user-host> IN CNAME `<autoUrl>` sandstorm-www.<user-host> IN TXT <public-id>
<user-host>is the hostname at which the user wishes to publish their site.
<public-id>plus the Sandstorm server hostname (as returned by
<server-host>is the hostname of the Sandstorm server (as returned by
Raw API example
See the Hacker CMS app, which can be installed from the app list or from source code.
Note: Provisional API
The current Cap'n Proto RPC for web publishing is hacky and not intended to be the long-term solution. In the long term, users will be able to connect domains to their Sandstorm account and then grant them to apps as capabilities through the Powerbox UI. Since the Powerbox and persistent capabilities are not yet implemented -- much less the ability to connect domains -- we are providing a hack so that developers can get started on such apps now. The hack allows a user to designate a Sandstorm app to host their domain via a special TXT record.
Also, the use of a C++ binary that you must embed might not be the
most convenient way to expose the Cap'n Proto API. We're considering
templates or a
postMessage-based API, and/or a
backend API that is part of
sandstorm-http-bridge. Let us know if
you have a preference for what you would like to use.
Why only static content?
In order to make per-user application instances cost-effective, a Sandstorm application server normally only runs while a user has the application open. This works very well for things like private documents which have only one or maybe a few users. A public web site, however, is intended to be viewed widely and at all hours of the day. If we had to spin up the application sever for every visit, we'd lose this key advantage.
By restricting web publishing to static content, we can avoid spinning up the application server for regular visits. Only editing the content requires the server to be active.