Skip to main content
Version: 1.0

Setting up HTTPS on your Shelly device

(Since firmware 2.0.0)

What is an HTTPS certificate and why do I need one?

When you access your Shelly device through a web browser or an API call, the communication normally happens over plain HTTP — unencrypted and readable by anyone on the same network. An HTTPS certificate enables encrypted (TLS) communication between your browser or application and the device, preventing eavesdropping and tampering.

Devices shipped from factory with firmware 2.0.0+ come with HTTPS already enabled using certificates issued by Shelly's internal PKI. Devices that were updated to firmware 2.0.0+ (but not originally shipped with it) do not have factory-provisioned certificates and serve only plain HTTP by default.

info

Without a certificate your device continues to work normally over HTTP — no action is required. Setting up HTTPS is only needed if you want encrypted access to your device.

Ways to obtain a certificate

There are two main approaches to enabling HTTPS on your device:

ApproachDifficultyBrowser warnings?Requirements
Self-signed certificateBasicYes — browsers will show a security warning because the certificate is not issued by a trusted authority. The connection is still encrypted.OpenSSL on your workstation
Trusted certificate (e.g. Let's Encrypt)AdvancedNo — browsers trust the certificate automatically.A domain name pointing to the device's local IP (e.g. via a local DNS server)

Both paths use the same RPC methods to upload the certificate to the device. You can also upload certificates through the Web UI under Settings → TLS Configuration.

RPC Methods for Server Certificates

Three dedicated RPC methods are available for managing the HTTPS server certificate. They follow the same interface as the existing Shelly.PutTLSClientCert and related methods used for outbound TLS.

Shelly.PutHTTPServerCert

Uploads or removes the HTTPS server certificate. The certificate is written to a file on the device's flash storage. A device reboot is required for changes to take effect.

Removal behavior: When removing the certificate (passing null or ""), the server key and CA bundle are also removed automatically. If the device has factory-provisioned certificates, they are restored; otherwise HTTPS is disabled.

Request

Parameters:

PropertyTypeDescription

data

string or null

PEM-encoded server certificate contents. Pass null or an empty string "" to remove the existing certificate. Required

append

boolean

If true, appends data to the existing file instead of replacing it. Useful for uploading large certificates in chunks. Defaults to false.

Response

When uploading (data is a non-empty string):

PropertyTypeDescription

len

number

Total size of the certificate file in bytes.

restart_required

boolean

Always true — a reboot is needed for the new certificate to take effect.

When removing (data is null or ""):

PropertyTypeDescription

restart_required

boolean

Always true — a reboot is needed for the change to take effect.

Shelly.PutHTTPServerKey

Uploads or removes the HTTPS server private key. The key is written to a file on the device's flash storage. A device reboot is required for changes to take effect.

Removal behavior: When removing the key (passing null or ""), the server certificate and CA bundle are also removed automatically. If the device has factory-provisioned certificates, they are restored; otherwise HTTPS is disabled.

Request

Parameters:

PropertyTypeDescription

data

string or null

PEM-encoded private key contents. Pass null or an empty string "" to remove the existing key. Required

append

boolean

If true, appends data to the existing file instead of replacing it. Useful for uploading large keys in chunks. Defaults to false.

Response

When uploading (data is a non-empty string):

PropertyTypeDescription

len

number

Total size of the key file in bytes.

restart_required

boolean

Always true — a reboot is needed for the new key to take effect.

When removing (data is null or ""):

PropertyTypeDescription

restart_required

boolean

Always true — a reboot is needed for the change to take effect.

Shelly.PutHTTPServerCABundle

Uploads or removes a CA certificate bundle used for client certificate authentication (mutual TLS). When a CA certificate is configured, the device will require connecting HTTPS clients to present a valid client certificate signed by this CA. Clients that do not present a valid certificate will be rejected.

This is optional — if no CA certificate is set, the device accepts any HTTPS connection without verifying the client's identity. Setting a CA certificate is useful when you want to restrict access to the device to clients that hold a certificate issued by your own certificate authority.

The CA certificate bundle is written to a file on the device's flash storage. The configuration stores a reference to this file, and the TLS library loads the certificate on demand during the TLS handshake.

Removal behavior: Removing the CA bundle only removes the CA — the server certificate and key remain intact.

Request

Parameters:

PropertyTypeDescription

data

string, empty string, or null

PEM-encoded CA certificate contents. Pass null or an empty string "" to remove the existing CA and disable client certificate verification. Required

append

boolean

If true, appends data to the existing CA file instead of replacing it. Useful for uploading large CA bundles in chunks. Defaults to false.

Response

When uploading (data is a non-empty string):

PropertyTypeDescription

len

number

Total size of the CA certificate file in bytes.

restart_required

boolean

Always true — a reboot is needed for the new CA to take effect.

When removing (data is null or ""):

PropertyTypeDescription

restart_required

boolean

Always true — a reboot is needed for the change to take effect.

Removal behavior

When you remove the certificate or key, the device automatically removes all three files (certificate, key, and CA bundle) to avoid leaving the device in a half-configured state. Removing only the CA bundle removes just the CA — the certificate and key are left intact.

If the device was shipped with factory-provisioned HTTPS certificates, removing user-uploaded certificates restores the factory certificates. Devices without factory certificates revert to HTTP-only operation.

caution

After uploading a certificate and key and rebooting, HTTPS becomes available on port 443. The plain HTTP listener on port 80 continues to operate but will redirect all requests to HTTPS when enhanced_security is enabled. This applies to devices with factory-provisioned HTTPS certificates (where enhanced_security is enabled by default) or when the user manually enables enhanced_security. Both cases apply starting from firmware 2.0.x. Use https://<device-ip> to access the device. Browsers and curl will show certificate warnings for self-signed certificates — use curl -k or add the certificate to your trust store.

Option A: Self-signed certificate

A self-signed certificate encrypts the connection but is not issued by a trusted certificate authority. Browsers and tools like curl will show a warning — this is expected and does not mean the encryption is weak.

Prerequisites

  • OpenSSL command-line tool installed on your workstation
  • Network access to the Shelly device

Step 1: Generate a Private Key

Generate an EC private key (P-256 curve). EC keys are preferred on embedded devices because they are smaller and faster than RSA:

openssl ecparam -genkey -name prime256v1 -noout -out server.key
Supported key types

We strongly recommend using ECC (Elliptic Curve) private keys rather than RSA. ECC keys are significantly smaller and faster to process, which matters on resource-constrained embedded devices.

The following EC curves are supported:

CurveOpenSSL nameRecommendedNotes
P-256 (secp256r1)prime256v1YesBest choice — smallest key, hardware-accelerated on Gen4 (ESP32-C6) devices
P-384 (secp384r1)secp384r1SuitableStronger security margin, software-only
P-521 (secp521r1)secp521r1SuitableLargest key size, software-only

RSA keys (2048-bit and above) are supported but not recommended — the TLS handshake will be noticeably slower and consume more RAM.

Step 2: Create an OpenSSL Configuration File

Create a file named openssl.cnf with the following contents. Replace 192.168.1.100 with the actual IP address of your Shelly device:

[req]
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = v3_req

[dn]
CN = Shelly Device

[v3_req]
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.1.100
tip

You can add multiple IP addresses or DNS names by adding more entries:

[alt_names]
IP.1 = 192.168.1.100
IP.2 = 10.0.0.50
DNS.1 = myshelly.local

Step 3: Generate a Certificate Signing Request (CSR)

openssl req -new -key server.key -out server.csr -config openssl.cnf

Step 4: Self-Sign the Certificate

Sign the certificate with a validity of 10 years (3650 days):

openssl x509 -req -in server.csr -signkey server.key \
-out server.crt -days 3650 \
-extensions v3_req -extfile openssl.cnf

Step 5: Verify the Certificate

openssl x509 -in server.crt -text -noout

Check that the output includes:

  • Subject: CN = Shelly Device
  • X509v3 Subject Alternative Name: with your IP address

Step 6: Upload the Certificate and Key to the Device

Upload the certificate using Shelly.PutHTTPServerCert:

curl -X POST -d "{
\"id\": 1,
\"method\": \"Shelly.PutHTTPServerCert\",
\"params\": {
\"data\": $(python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' < server.crt)
}
}" http://${SHELLY}/rpc

Upload the private key using Shelly.PutHTTPServerKey:

curl -X POST -d "{
\"id\": 1,
\"method\": \"Shelly.PutHTTPServerKey\",
\"params\": {
\"data\": $(python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' < server.key)
}
}" http://${SHELLY}/rpc

Step 7: Reboot the Device

The HTTP server reads certificate configuration at startup. A reboot is required for changes to take effect:

http://192.168.33.1/rpc/Shelly.Reboot

Step 8: Verify HTTPS is Working

After the device reboots, connect using HTTPS. The -k flag is needed because self-signed certificates are not trusted by default:

curl -k https://${SHELLY}/rpc/Shelly.GetDeviceInfo

To verify the certificate being served matches your generated certificate:

openssl s_client -connect ${SHELLY}:80 -showcerts </dev/null 2>/dev/null | \
openssl x509 -text -noout | grep -E "Subject:|Alternative|IP Address"

Option B: Trusted certificate (Let's Encrypt)

A certificate issued by a trusted authority such as Let's Encrypt eliminates browser warnings entirely. This approach is more involved because Let's Encrypt must verify that you control the domain name associated with the certificate.

Prerequisites

  • A domain name (e.g. myshelly.example.com) that resolves to your device's local IP address. This is typically configured on a local DNS server or in your router's DNS settings.
  • Certbot or another ACME client installed on your workstation.
  • The ability to complete a DNS-01 challenge (required because the device is on a local network and not reachable from the internet).

Step 1: Request a Certificate via DNS-01 Challenge

Because the device is on a private network, you cannot use the default HTTP-01 challenge. Use the DNS-01 challenge instead — this requires adding a TXT record to your domain's DNS:

certbot certonly --manual --preferred-challenges dns \
-d myshelly.example.com

Certbot will ask you to create a DNS TXT record for _acme-challenge.myshelly.example.com. Add the record through your DNS provider, wait for propagation, then press Enter to continue.

Step 2: Locate the Certificate Files

After successful verification, Certbot stores the certificate files (typically under /etc/letsencrypt/live/myshelly.example.com/):

  • fullchain.pem — the server certificate + intermediate CA chain
  • privkey.pem — the private key

Step 3: Upload to the Device

Upload using the same RPC methods as for self-signed certificates. Use fullchain.pem (not cert.pem) to include the full certificate chain:

curl -X POST -d "{
\"id\": 1,
\"method\": \"Shelly.PutHTTPServerCert\",
\"params\": {
\"data\": $(python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' < /etc/letsencrypt/live/myshelly.example.com/fullchain.pem)
}
}" http://${SHELLY}/rpc
curl -X POST -d "{
\"id\": 1,
\"method\": \"Shelly.PutHTTPServerKey\",
\"params\": {
\"data\": $(python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' < /etc/letsencrypt/live/myshelly.example.com/privkey.pem)
}
}" http://${SHELLY}/rpc

Step 4: Reboot and Verify

http://192.168.33.1/rpc/Shelly.Reboot

After reboot, verify with:

curl https://myshelly.example.com/rpc/Shelly.GetDeviceInfo

No -k flag is needed — the certificate is trusted.

note

Let's Encrypt certificates are valid for 90 days. You will need to repeat the renewal and upload process before the certificate expires. Consider automating this with a script that runs certbot renew and re-uploads the new certificate via Shelly.PutHTTPServerCert.

Client Certificate Authentication (Mutual TLS)

By default, HTTPS on the device only authenticates the server — the client knows it is talking to the right device, but the device accepts connections from anyone. By uploading a CA certificate with Shelly.PutHTTPServerCABundle, you can enable mutual TLS (mTLS): the device will require each connecting client to present a certificate signed by that CA.

When to use this

  • You want to restrict API access to authorized clients only (e.g. a home automation controller that holds a client certificate).
  • You are deploying devices on a network where password-based authentication alone is not sufficient.

How it works

  1. You create your own Certificate Authority (CA) and generate client certificates signed by it.
  2. Upload the CA certificate to the device using Shelly.PutHTTPServerCABundle.
  3. Reboot the device.
  4. When a client connects over HTTPS, it must present a certificate signed by your CA. If it does not, the TLS handshake is rejected.

Connecting with a client certificate

After uploading the CA and rebooting, curl without a client certificate will fail:

# This will fail — no client certificate presented
curl -k https://${SHELLY}/rpc/Shelly.GetDeviceInfo

Provide the client certificate and key to authenticate:

curl -k --cert client.crt --key client.key \
https://${SHELLY}/rpc/Shelly.GetDeviceInfo

Removing client certificate authentication

To stop requiring client certificates, remove the CA by passing null or an empty string, then reboot:

http://192.168.33.1/rpc/Shelly.PutHTTPServerCABundle?data=null

Response

{
"restart_required": true
}
http://192.168.33.1/rpc/Shelly.Reboot

Both null and an empty string "" are accepted and have the same effect — the CA certificate file is deleted from flash and the configuration is reset to default. After reboot, the device will accept HTTPS connections without requiring a client certificate.

Removing a Custom Certificate

To revert to plain HTTP, remove the certificate and key by passing null, then reboot:

http://192.168.33.1/rpc/Shelly.PutHTTPServerCert?data=null
http://192.168.33.1/rpc/Shelly.PutHTTPServerKey?data=null
http://192.168.33.1/rpc/Shelly.Reboot

After reboot, the device will be accessible via plain HTTP again on port 80.

tip

If you also had a CA certificate configured for client authentication, remove it as well:

http://192.168.33.1/rpc/Shelly.PutHTTPServerCABundle?data=null

Examples

Shelly.PutHTTPServerCert example

http://192.168.33.1/rpc/Shelly.PutHTTPServerCert?data="-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n"

Response

{
"restart_required": true
}

Shelly.PutHTTPServerKey example

http://192.168.33.1/rpc/Shelly.PutHTTPServerKey?data="-----BEGIN EC PRIVATE KEY-----\nMHQC...\n-----END EC PRIVATE KEY-----\n"

Response

{
"restart_required": true
}

Shelly.PutHTTPServerCABundle example

http://192.168.33.1/rpc/Shelly.PutHTTPServerCABundle?data="-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n"

Response

{
"len": 753,
"restart_required": true
}

Removing the server certificate

http://192.168.33.1/rpc/Shelly.PutHTTPServerCert?data=null

Response

{
"restart_required": true
}

Removing the CA certificate (disable client authentication)

Using null:

http://192.168.33.1/rpc/Shelly.PutHTTPServerCABundle?data=null

Response

{
"restart_required": true
}