Enabling support for mutual TLS (mTLS) on the Screenly side is straightforward. This allows your web servers to cryptographically verify that incoming requests are originating exclusively from authorized Screenly devices.
Prerequisites
Hardware
Screenly Player, Screenly Player Max, Raspberry Pi 4, Raspberry Pi 5
Firmware
ScreenlyOS version 26.2.0 or newer
Step 1: Download the Device Certificate
To allow connections on your web server, you first need the public certificate from your Screenly device.
- Navigate to your screen in the Screenly dashboard.
- Click Settings.
- Select View Certificate.
- Click download to save the file. The file will be formatted similar to srly-y358c2nss7i40ly.pem.
Repeat this step for every screen that requires access to the secure web page.
Step 2: Enable mTLS on the Web Page Asset
Configure the Screenly platform to present the device certificate when loading your specific web page.
- Add your web page to the Content Library, or open an existing web page asset.
- Click Advanced.
- Toggle the Allow sending client certificate option to enable it.
- Click Save to apply the changes.
Step 3: Web Server Configuration Overview
Screenly issues self-signed public certificates for each device. Because these do not rely on an external Certificate Authority (CA), your web server must be configured to trust the specific Screenly .pem files directly.
If you are authenticating a single Screenly device, you can point your web server directly to the downloaded .pem file. If you are authorizing multiple screens, you must combine all their downloaded certificates into a single Trust Store Bundle:
cat srly-device1.pem srly-device2.pem > screenly_trusted_devices.pemStep 4: Web Server Configuration Examples
Below are configuration examples for common web servers to accept requests exclusively from your authorized Screenly certificates.
NGINX
Nginx requires all trusted client certificates to be concatenated into a single bundle file.
server {
listen 443 ssl;
server_name internal.yourdomain.com;
# Standard Server TLS
ssl_certificate /path/to/server.crt;
ssl_certificate_key /path/to/server.key;
# Screenly mTLS Configuration
ssl_verify_client on;
ssl_client_certificate /path/to/screenly_trusted_devices.pem;
location / {
# Optional: Pass the Screenly device ID to your backend app
proxy_set_header X-Device-ID $ssl_client_s_dn_cn;
proxy_pass http://localhost:8080;
}
}Apache HTTP Server
Apache can read certificates directly from a directory, making it easy to manage multiple Screenly devices without concatenating files. Place all downloaded srly-*.pem files into a dedicated directory and run c_rehash /path/to/screenly_certs/.
<VirtualHost *:443>
ServerName internal.yourdomain.com
SSLEngine on
SSLCertificateFile /path/to/server.crt
SSLCertificateKeyFile /path/to/server.key
# Screenly mTLS Configuration
SSLVerifyClient require
SSLVerifyDepth 1
# Point to the hashed directory of Screenly device certificates
SSLCACertificatePath "/path/to/screenly_certs/"
<Location />
RequestHeader set X-Device-ID "%{SSL_CLIENT_S_DN_CN}s"
ProxyPass "http://localhost:8080/"
</Location>
</VirtualHost>HAProxy
HAProxy handles mTLS at the frontend termination layer using the bundled file of trusted Screenly certificates.
frontend https_in
# Bind to 443, specify server cert, and require verification against the Screenly bundle
bind *:443 ssl crt /path/to/server_bundle.pem ca-file /path/to/screenly_trusted_devices.pem verify required
http-request set-header X-Device-ID %{+Q}[ssl_c_s_dn(cn)]
default_backend app_servers
backend app_servers
server app1 127.0.0.1:8080Caddy
Caddy verifies incoming client certificates natively within the tls block. Point the trusted_ca_certs directive to your concatenated .pem bundle.
internal.yourdomain.com {
tls /path/to/server.crt /path/to/server.key {
# Screenly mTLS Configuration
client_auth {
mode require_and_verify
trusted_ca_certs /path/to/screenly_trusted_devices.pem
}
}
reverse_proxy localhost:8080 {
header_up X-Device-ID {tls_client_subject_cn}
}
}Alternative: Infrastructure-Level mTLS Options
If you prefer not to manage mTLS configuration directly on your individual web servers, or if your organization uses cloud-native networking infrastructure, you can offload the verification of Screenly devices to the edge or gateway level.
1. Edge Providers and CDNs (Cloudflare, Fastly)
Instead of forcing your internal web servers to process the cryptographic mTLS handshake from Screenly devices, you can offload the entire process to your edge network provider.
If your organization uses a service like Cloudflare, you can upload the Screenly device certificates (or a combined .pem bundle of your screens) directly to Cloudflare Access.
- How it works: When a Screenly player attempts to load your private web page, Cloudflare intercepts the connection at its nearest edge data center and validates the screen's certificate. If valid, Cloudflare passes the clean traffic through to your internal host.
- Why it's beneficial: It completely shields your company's internal infrastructure from unauthorized traffic. Unverified entities trying to guess the URL of your dashboards are dropped at the edge before hitting your corporate network.
2. API Gateways and Load Balancers (AWS ALB, Kong, Apigee)
If your internal dashboards or data visualizations are routed through a centralized corporate API Gateway or an Enterprise Application Load Balancer, you can terminate the Screenly mTLS connection there.
- How it works: You configure mTLS on your gateway or load balancer (for example, using AWS Application Load Balancer's native mTLS support). You upload the trusted Screenly .pem bundle to your secure cloud storage, link it to the listener, and the infrastructure automatically handles the validation.
- Why it's beneficial: It isolates your security configuration. Your internal development teams can focus on building dashboards on standard HTTP/HTTPS, while your network team manages the device access control centrally.
Handling Mixed Traffic (Screenly Players + Corporate Users)
A common challenge is managing a single web asset or dashboard domain that needs to be viewed by both standard corporate employees (using normal browsers) and automated Screenly digital signage displays (using mTLS).
To prevent employees from receiving "Missing Client Certificate" errors when trying to view a report, you have two primary deployment strategies:
Strategy A: Subdomain Routing (Highly Recommended)
The cleanest way to handle mixed traffic is to split the access point at the DNS and routing level. You create two paths to the exact same backend content:
- dashboards.yourcompany.com - Configured for standard corporate TLS (or integrated with your SSO like Okta/Azure AD). Corporate employees use this URL to log in and look at data. No client certificates are requested.
- screenly.yourcompany.com - Configured for strict mTLS. You paste this URL into your Screenly asset settings. Only Screenly players holding a valid device certificate can resolve this address; any standard browser attempting to hit it is instantly rejected.
Strategy B: "Optional" mTLS via NGINX (Same Domain)
If you are constrained to using a single URL for both humans and displays, you can configure your ingress proxy to use "Optional" mTLS. Instead of dropping connections that lack a certificate, the proxy evaluates the request conditionally.
Here is an example of how to configure an NGINX proxy to allow standard corporate users onto a public dashboard path, while locking down a strict screen endpoint on the exact same domain:
Nginx
server {
listen 443 ssl;
server_name dashboards.yourcompany.com;
ssl_certificate /path/to/corporate_server.crt;
ssl_certificate_key /path/to/corporate_server.key;
# 1. Set verify to OPTIONAL instead of ON
ssl_verify_client optional;
ssl_client_certificate /path/to/screenly_trusted_devices.pem;
# 2. Public path: Employees can view this normally
location /employee-view {
proxy_pass http://internal_dashboard_cluster;
}
# 3. Secure path: Only Screenly players can access this
location /signage-feed {
# If the client did not present a verified Screenly cert, turn them away
if ($ssl_client_verify != "SUCCESS") {
return 403 "Forbidden: Valid Screenly device certificate required.";
}
# Optional: Forward the specific screen's ID to your app for tracking
proxy_set_header X-Screen-ID $ssl_client_s_dn_cn;
proxy_pass http://internal_dashboard_cluster;
}
}