HTTPS
Figwheel is currently working to make using HTTPS locally as easy as setting
:use-ssl
totrue
in your Figwheel Options.
It’s important to remember that you may not need the figwheel server
to use HTTPS. If you are serving your application from your own
server and that server is using HTTPS then
connecting to a local websocket (for Figwheel) should not require an
SSL connection. Another thing to note is that connections from a
secure web page to 127.0.0.1
rather than localhost
do not require
an SSL connection either.
If you are serving your application via the Figwheel server and decide you want to use HTTPS, Figwheel tries to make this as easy as possible.
You can use :use-ssl true
to help you configure the Figwheel server to use SSL but let’s look at
the manual configuration first.
Manual configuration
We’ll start with a basic Figwheel Main configuration in dev.cljs.edn
like:
{:main example.core}
Configure Jetty
We’ll want to add the SSL configuration to :ring-server-options
:
^{:ring-server-options {:ssl? true
:ssl-port 9533
:keystore <path-to-java-key-store>
:key-password <password-for-key-store>}}
{:main example.core}
These options tell the ring.jetty.adapter
to use SSL. You’ll have to
replace <path-to-java-key-store>
and <password-for-key-store>
with
the actual values from our own Java KeyStore.
A Java KeyStore is a bundle of certificates and keys. The keys are needed to sign server responses so that clients know that they are valid.
Using certifiable to create a keystore
You can use certifiable to create a Java key store.
Certifiable is designed create a safe certificate for local use. On the MacOS platform it also adds trust for that certificate so that your browsers don’t complain about it. Its main advantage is that it works with tools that are already installed if you are running Clojure. It is also very safe to use.
Certifiable is a dependency of Figwheel so you can call it easily on the command line.
Make sure you add any -A
aliases needed to include the
com.bhauman/figwheel-main
dependency and call:
$ clj -m certifiable.main
This will generate a certificate for you and finally output something like this:
--------------------------- Setup Instructions ---------------------------
Local dev Java keystore generated at: /Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-server.jks
The keystore type is: "JKS"
The keystore password is: "password"
The root certificate is: /Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-root-trust-this.pem
For System: root certificate is trusted
For Firefox: root certificate is trusted
Example SSL Configuration for ring.jetty.adapter/run-jetty:
{:ssl? true,
:ssl-port 9533,
:keystore "/Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-server.jks",
:key-password "password"}
The last few lines of the output is an example of the configuration
you need to pass to :ring-server-options
.
So given the above certifiable command we can finish the
:ring-server-options
config in our dev.cljs.edn
like so:
^{:ring-server-options {:ssl? true
:ssl-port 9533
:keystore "/Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-server.jks"
:key-password "password"}}
{:main example.core}
Using mkcert to create a keystore
Another option is the mkcert
tool.
Mkcert will create and set up trust for a certificate as well.
Follow the instructions to install mkcert
. (i.e. brew install mkcert
on MacOS).
You can then ensure that its root certificate is installed and trusted by running:
$ mkcert -install
To create a keystore that Jetty will understand, we will instruct
mkcert
to generate a PKCS#12
bundle.
You can create a keystore for localhost
by running:
$ mkcert -pkcs12 localhost
This will output a localhost.p12
file in your current directory.
We can utilize this certificate/key bundle in our config like so:
^{:ring-server-options {:ssl? true
:ssl-port 9533
:keystore "localhost.p12"
:keystore-type "PKCS12" ;; <- IMPORTANT!
:key-password "changeit"}}
{:main example.core}
Be sure to indicate the keystore type is PKCS12
.
Why use certifiable
over mkcert
?
mkcert
is a robust popular tool. mkcert
creates one root
certificate and then keeps the keys for that certificate on your
machine so it can create more leaf certificates from a single trusted
root. This is potentially hazardous as you have trusted a root
certificate that someone may be able to obtain the keys for, allowing
an attacker to create trusted certificates for arbitrary sites like
google.com. certifiable
trades off ease of use
for safety, it creates a new root certificate for each leaf certificate
and then deletes all the keys for the root certificates. This requires
you to trust each root certificate individually but guarantees that no
new certificates can be created for that trusted root.
Configure :connect-url
and :open-url
You’ll want the connection to Figwheel to go over SSL so we’ll need
to change the :connect-url
to
"wss://[[config-hostname]]:9533/figwheel-connect"
You’ll also want the browser that pops open after the build starts to
be an https
URL as well. You can do this by setting
:open-url
to "https://[[server-hostname]]:9533"
It’s important to remember that both [[config-hostname]]
and
[[server-hostname]]
are template variables that are filled in by
Figwheel.
Complete manual config
So our finished configuration will something like:
^{:connect-url "wss://[[config-hostname]]:9533/figwheel-connect"
:open-url "https://[[server-hostname]]:9533"
:ring-server-options {:ssl? true
:ssl-port 9533
:keystore "/Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-server.jks"
:key-password "password"}}
{:main example.core}
:use-ssl
syntactic sugar and automation
:use-ssl
attempts to set all of the above options for you
automatically. It will try to use
Certifiable to create or
reuse an existing certificate for localhost if neither :keystore
or
:truststore
are set already.
So you could just set :use-ssl
to true
like so:
^{:use-ssl true}
{:main example.core}
And that may work, if you need to supply your own certificate and you can easily do that like so:
^{:ring-server-options {:keystore "/Users/bhauman/_certifiable_certs/localhost-1d070e4/dev-server.jks"
:key-password "password"}}
{:main example.core}
:use-ssl
will not override any configuration that you provide.
Providing a custom hostname with :ssl-valid-hosts
If you need a custom local hostname to be added to the certificate generated by Certifiable.
For instance if you have already added test.example.com
to your
/etc/hosts
file and youd like your the SSL certificate to support
test.example.com
you can use the :ssl-valid-hosts
configuration
option.
^{:use-ssl true
:ssl-valid-hosts ["test.example.com" "localhost" "test.localhost"]}
{:main example.core}
Conclusion
The above should get you up and running will SSL and Figwheel. You
should rely on :use-ssl
when possible.