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:
- Customizing certificate information.
- Pre-generated CSR.
- Proof of .onion possession command.
- 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:
-
Installing mkcert onto the machine which will be running Onionspray.
-
Configuring a custom Certificate Authority for the certificates that you will need, using
mkcert -install
. The location for the CA files can be shown withmkcert -CAROOT
. -
Adding
set ssl_mkcert 1
to project configurations, and yourmkcert
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.