Skip to content

HTTPS Certificates for Onionspray

Configuration

Onionspray generates a Certificate Signing Request (CSR) and also a self-signed certificate for every onionsite it manages.

The CSR and self-signed certificate parameters can be customized by creating an onionspray-certs.conf file in the main Onionspray folder.

Updating existing certificates and CSRs

Changes in certificate configuration aren't automatically applied to existing certificates and CSRs.

It's advised to first try a few times to tune the configuration and only then use the CSR or self-signed certificate.

The following is an example configuration:

#
# Certificate configuration for Onionspray.
#
# Copyright (C) 2025 The Tor Project, Inc.
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This file is sourced by Onionspray's make-selfsigned-wildcard-ssl-cert.sh
#
# Generated by Ansible:
# https://gitlab.torproject.org/tpo/onion-services/ansible/onionspray-role
#

# Certificate lifetime
ONIONSPRAY_CERT_DAYS="365"

# CountryName
ONIONSPRAY_CERT_COUNTRY_NAME="AQ"

# StateOrProvinceName
ONIONSPRAY_CERT_STATE_PROVINCE_NAME="Internet"

# LocalityName
ONIONSPRAY_CERT_LOCALITY_NAME="Onion Space"

# OrganizationName
ONIONSPRAY_CERT_ORGANIZATION_NAME="TLS Onion Space"

# OrganizationalUnitName
ONIONSPRAY_CERT_ORGANIZATION_UNIT_NAME="Onion Service Certificate"

After editing the certificate generation, you may proceed to the next section in order to get your custom self-signed certificates or CSRs.

Self-signed certificate and CSR generation

As stated in the previous section, Onionspray generates a Certificate Signing Request (CSR) and also a self-signed certificate for every onionsite it manages.

If you need to regenerate TLS keys, self-signed certificates and CSRs by any reason, like certificate renewal or configuration update, use regenerate-tls-keys command (also works with the regen-tls alias):

./onionspray regen-tls <project> <onion_address>

Example:

./onionspray regen-tls myproject exaeqn47yirrpyo6lt2rlg22m4gq7grszejt4kpwekcnrphdhx2kl2yd.onion

Built-in backups

This command backs up any existing TLS keys, CSRs and certificates into the project folder, so you can rollback to your previous keys and certificates if needed.

Even if this backup procedure, it's advised to always keep (encrypted) backups of your keys and certificates, just in case.

Regenerates everything TLS from an onionsite

Despite doing backups for your previous TLS key and certificate material, this command generates new keys, CSRs and self-signed certificate.

This means that if you had previously a CA-validated certificate, it will be replaced by a self-signed certificate and a new CSR file that can be used to get a new CA-validated cert.

A previous CA-validated will be saved in the backup folder.

Onionspray with self-signed certificates

Onionspray already generates a self-signed HTTPS certificate for each proxied website, valid for 365 days by default.

Self-signed certificate issues

When connecting to Onion Services using self-signed HTTPS certificates, you may encounter many "broken links" which are due to the HTTPS certificate not being validated by a Certificate Authority (CA).

This mostly depends on the web browser you're using, which may or may not consistently support self-signed certificates.

While using self-signed certificates is fine for testing purposes, and some people even use it on production systems, you may also want to consider a CA-validated certificate, which is detailed in another section down this document.

Handling self-signed certificate warnings

For clients that presents a warning message when browsing an Onion Service with self-signed certificates, a handy /hello-onion/ endpoint is provided by default by Onionspray.

Example:

https://exaeqn47yirrpyo6lt2rlg22m4gq7grszejt4kpwekcnrphdhx2kl2yd.onion/hello-onion/

This /hello-onion/ is internally served by Onionspray and provides a stable, fixed URL for quickly accepting a certificate in the web browser.

Another effective solution is to open all the broken links, images and resources "in a new Tab" and accept the self-signed certificate there.

In production, of course, one would expect to use a CA-validates certificate to provide identity and assurance to an onion site, rendering these issues moot.

Renewing the self-signed certificate

Renewing the self-signed certificates means regenerating new ones, which can be done any time, usually some days or weeks before the current certificate expires.

After regenerating your certificate, make sure to restart the service so Onionspray loads it in the proxy service:

./onionspray bounce myproject

Onionspray with CA-issued certificates

The default, self-signed certificates generated by Onionspray aren't automatically validated by a Certificate Authority (CA), which is something to consider.

If you choose to get an Onion HTTPS certificate from a CA, what will happen, and what will you need to do?

The specific procedure varies from CA to CA, but Onionspray leaves some things ready depending on what you need:

  1. Customizing certificate information.
  2. Pre-generated CSR.
  3. Proof of .onion possession command.
  4. Quick procedure for importing a CA-validated certificate.

1. Customizing certificate information

This is detailed in the configuration section above.

2. Pre-generate CSR

As detailed in the generation section above, Onionspray leaves a CSR as a .csr file in the project's SSL folder.

For a project named myproject, this file will be available at projects/myproject/ssl.

This CSR is ready to use with a CA.

3. Proof of .onion possession command

The CSR is not enough for getting a CA-issued certificate.

Additionally, some Proof of Possession (PoP) of the .onion address is also required.

Check here for the up-to-date validation methods available for .onion addresses.

The methods supported by Onionspray are detailed below.

Using onion-csr

This involves producing an additional CSR, this time signed by the Onion Service private key (and not by the TLS private key) and containing an specific cryptographic nonce (i.e, a shared secret to be used only once), like using the onion-csr tool.

Onionspray supports onion-csr by bundling it through Onionmine, an Onion Services keys and certificate generator, available as a Git submodule in the vendors folder.

The onion-csr proof of possession is accessed via the prove-possession command, which requires a nonce (provided by the CA during the certificate issue procedure):

./onionspray prove-possession <onion-address> onion-csr <nonce>

For an hypothetical exav2agnwayz4hxbm2elifyn25ivey7pg7glg676nz2udsobbvsihkad.onion and a nonce of abcefghijklmnopq, we would have:

./onionspray prove-possession exav2agnwayz4hxbm2elifyn25ivey7pg7glg676nz2udsobbvsihkad onion-csr abcefghijklmnopq
-----BEGIN CERTIFICATE REQUEST-----
MIIBBzCBugIBADAAMCowBQYDK2VwAyEAJcFdAM2wMZ4e4WaItBcN11FSY+83zLN7
/m51QcnBDWSggYYwFAYEZ4EMKjEMBAqyNmcW2imlmQZEMBIGBGeBDCkxCgQIq87w
EjRWeJowWgYJKoZIhvcNAQkOMU0wSzBJBgNVHREEQjBAgj5leGF2MmFnbndheXo0
aHhibTJlbGlmeW4yNWl2ZXk3cGc3Z2xnNjc2bnoydWRzb2JidnNpaGthZC5vbmlv
bjAFBgMrZXADQQDvx717ZrbmWSaZ1MSnvKTxSnsMJ/vywzozc65Z7w15SsMWEprM
qsJFb563c7z7V68GHsUpteQqmJaTY/bwqUAJ
-----END CERTIFICATE REQUEST-----

The resulting Certificate Request can then be passed to the CA validation procedure.

Using Agreed-Upon Change to Website

The CA might offer you the option to post a secret key at a particular URL on your onion site; the message will read something like:

Place the file FILENAME to http://ONIONADDRESS.onion/.well-known/pki-validation/

... and they will offer you a file to download.

Download this file, and open it with a text editor; the content will be a long secret string, like THISISAREALLYLONGHEXADECIMALSECRET.

Add a line to your Onionspray configuration, substituting the values where necessary:

set ssl_proof_csv /.well-known/pki-validation/FILENAME,THISISAREALLYLONGHEXADECIMALSECRET

Then do something like:

onionspray config projectname.conf && onionspray nxreload projectname

... to install the URL handlers.

The proceed with the other steps detailed by the CA.

Optional: what if you have multiple Onion addresses?

You can put multiple path,value strings into ssl_proof_csv, space-separated; use trailing backslashes to put entries onto separate lines:

set ssl_proof_csv \
    /.well-known/pki-validation/key1,value1 \
    /.well-known/pki-validation/key2,value2 \
    /.well-known/pki-validation/key3,value3
Optional: what if your multiple "proof" URLs all have the SAME pathname?

The ssl_proof_csv hack works if all the proof URLs are different; but if the CA were to give you the same pathname (e.g. /.well-known/pki-validation/fileauth.txt) for all of the onions, what do you do?

Answer: you use "splicing". If you have onion addresses named xxxxxxxxxxxxxxxx and yyyyyyyyyyyyyyyy, then you can create files:

  • templates/nginx-site-xxxxxxxxxxxxxxxx.onion.conf
  • templates/nginx-site-yyyyyyyyyyyyyyyy.onion.conf

... and into each put something similar to the following incantation; customise as necessary:

    location = "/.well-known/pki-validation/fileauth.txt" {
      return 200 "RESPECTIVE-PROOF-STRING-GOES-HERE";
    }

... then when you next onionspray config and onionspray nxreload, that code should be spliced into the correct configuration for each onion.

4. Quick procedure for importing a CA-validated certificate

For each certificate, the CA will offer you several files to download.

Onionspray needs an unencrypted "PEM Bundle" file containing the certificate and some parent certs in the chain of trust.

If the "PEM Bundle" is available, download this file and copy it to your Onionspray server.

If the CA does not provide this file ready to use, you'll have to concatenate these certificates yourself.

Do not add the private key

When building the PEM Bundle certificate file, DO NOT INCLUDE THE TLS PRIVATE KEY.

Next, go to ~/onionspray/projects/PROJECTNAME/ssl folder. There you should see the development certificates, which will look like:

SHORT_ONIONADDRESS-v3.onion.cert
SHORT_ONIONADDRESS-v3.onion.pem

where SHORT_ONIONADDRESS-v3 is the same as the name of the address subfolder under your project, e.g. foo13majanhxc6x-v3.

There are two steps to installation:

  • Step 1: copy the PEM Bundle file from HARICA, on top of SHORT_ONIONADDRESS-v3.onion.cert.
  • Step 2: optionally, only the private key is saved in an encrypted file (not Onionspray default), you need to unlock and extract (or rename) the private key, by using a command such as:
    openssl ec -in privateKey.pem -out SHORT_ONIONADDRESS-v3.onion.pem
    

... and typing in the password that you chose during the CSR setup, earlier; if you chose to use RSA as the algorithm, you will need to use openssl rsa ... instead.

If you manually created the CSR, then rename the SHORT_ONIONADDRESS.key file the CSR generated to SHORT_ONIONADDRESS-v3.onion.pem.

Then: change directory back to the Onionspray directory, and do onionspray nxreload projectname, and test it.

Onionspray with a custom Certificate Authority

Onionspray supports custom Certificate Authorities, which may be useful for development purposes or special use-cases.

This can be done by:

  1. Installing mkcert onto the machine which will be running Onionspray.

  2. Configuring a custom Certificate Authority for the certificates that you will need, using mkcert -install. The location for the CA files can be shown with mkcert -CAROOT.

  3. Adding set ssl_mkcert 1 to project configurations, and your mkcert root certificate will be used to sign the resulting onion certificates. You can install that certificate into your local copy of Tor Browser; of course it will not work for anyone else.