BrightSign Proxy configuration
Some networks require devices to reach the internet through an HTTP proxy. This guide covers how to configure that proxy on a BrightSign player, which bypass entries signageOS needs, and how the behaviour differs between the two ways signageOS can run on BrightSign.
Before you start: which mode is the device running?
The proxy is a device-level network setting — it is stored once in the player's network configuration, and every method below writes to that same place. What differs is which methods are available to you.
| CoreApp / CloudControl | Supervisor | |
|---|---|---|
| What it is | CoreApp runs as a BrightScript autorun plus an Applet HTML application | CoreApp runs as a BrightSign OS extension (a Node.js process), with no BrightScript application of ours |
| BrightScript | ✅ available | ⛔ no autorun runs |
| Applet JS API | ✅ available | ⛔ applets are not supported |
| Custom Scripts | ✅ available (browser runtime) | ✅ available (nodejs runtime) |
Whichever method you use, localhost and 127.0.0.1 must not be routed through the proxy.
CoreApp runs a local HTTP service on the player for file access, and sending that traffic to a proxy breaks content playback.
Required proxy bypass
The bypass list is stored on the device alongside the proxy address, and every method below writes it.
nc.SetProxyBypass(["localhost", "127.0.0.1"])
From the management API the bypass list is the fifth argument of setManual():
await sos.management.proxy.setManual('proxy-server.domain.com', 83, '', '', ['localhost', '127.0.0.1']);
Add your own local hosts to the same list — for example an on-premise server or a local media source:
nc.SetProxyBypass(["localhost", "127.0.0.1", "media.internal.example.com"])
The bypass list is written on every setManual() call, so omitting the fifth
argument stores an empty one and clears whatever was on the device — including a list configured with BrightScript. Always pass the
complete list you want the device to end up with. disable() clears the proxy and the bypass list together.
On the Supervisor, loopback (127.0.0.0/8, ::1), private ranges
(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7) and link-local addresses (169.254.0.0/16, fe80::/10) are always routed
directly, whether or not they appear in the bypass list. The explicit entries above are still required for CoreApp, and are still worth
setting so the configuration behaves the same in both modes.
Option 1 — BrightScript
The traditional method, and the only one available before the device is connected to signageOS. Place this in your custom.brs hook or your
own autorun:
nc = CreateObject("roNetworkConfiguration", 0)
nc.SetProxy("http://proxy-server.domain.com:83")
nc.SetProxyBypass(["localhost", "127.0.0.1"])
nc.Apply()
With a username and password:
nc = CreateObject("roNetworkConfiguration", 0)
nc.SetProxy("http://username:password@proxy-server.domain.com:83")
nc.SetProxyBypass(["localhost", "127.0.0.1"])
nc.Apply()
Apply() persists the setting, so it survives reboots and does not need to be re-applied on every start. See
Integration of custom BrightScript for where to put this code.
This writes the same device network configuration that the Supervisor reads, so a player provisioned with BrightScript and later switched to the Supervisor keeps its proxy.
Option 2 — Applet JS API
From an applet you can read and change the proxy at runtime through sos.management.proxy:
// Set a proxy — note the port is a number here
await sos.management.proxy.setManual('proxy-server.domain.com', 83, '', '', ['localhost', '127.0.0.1']);
// With credentials
await sos.management.proxy.setManual('proxy-server.domain.com', 83, 'username', 'password', ['localhost', '127.0.0.1']);
// Inspect the current state
const enabled = await sos.management.proxy.isEnabled();
const connectedTo = await sos.management.proxy.getConnectedTo();
const bypassList = await sos.management.proxy.getBypassList();
// Remove the proxy and the bypass list
await sos.management.proxy.disable();
Pass the username and password exactly as they are. Characters that would need escaping in a URL are encoded when the value is stored and decoded again when the connection is opened.
The fifth argument is the bypass list, and it is written on every call — pass the complete list each time, as described in Required proxy bypass. Empty and whitespace-only entries are dropped before the list is stored.
Applets do not run on the Supervisor. Use a Custom Script instead.
Option 3 — Custom Script
Custom Scripts work in both modes, and are the supported way to configure a proxy on device
remotely. The runtime depends on the mode: use nodejs for the Supervisor and browser for CoreApp / CloudControl. The script body itself
is the same, because both runtimes expose sos.management.proxy.
{
"name": "brightsign-proxy",
"version": "1.0.0",
"description": "Configure the device HTTP proxy",
"dangerLevel": "high",
"platforms": {
"brightsign": {
"rootDir": "brightsign",
"mainFile": "setProxy.js",
"runtime": "nodejs"
}
},
"configDefinition": []
}
async function run() {
await sos.management.proxy.setManual('proxy-server.domain.com', 83, 'username', 'password', ['localhost', '127.0.0.1']);
// Report the result so you can see it in Box
const connectedTo = await sos.management.proxy.getConnectedTo();
const bypassList = await sos.management.proxy.getBypassList();
postResult(JSON.stringify({ connectedTo: connectedTo, bypassList: bypassList }, null, 2));
}
run();
To remove the proxy and the bypass list, call await sos.management.proxy.disable() instead.
If you point a device at a proxy it cannot reach, you lose the management connection to it — and you then cannot send another script to undo it. Recovery requires DWS, the local network, or physical access.
Verify the proxy is reachable from the device's network first, and test on a single device before rolling out.
How CoreApp / CloudControl uses the proxy
CoreApp runs as a BrightScript application together with an HTML application, and its parts reach the network in different ways:
- The HTML application uses the player's own network stack, so it follows the device proxy and the bypass list automatically. This is
exactly why
localhostand127.0.0.1have to be bypassed — the local file service runs over HTTP on the player itself. - Content, firmware and application downloads, and screenshot uploads are transferred with
curlusing the configured proxy.
Things worth knowing:
- The bypass list does not apply to file transfers. Downloads and uploads go through the proxy whenever one is configured, even for hosts you listed as bypassed. If you serve content from a local server, make sure the proxy can reach it.
- BrightScript writes one network interface, the management API writes the device configuration.
roNetworkConfigurationapplies to the interface it was opened with, so a player that moves between Ethernet and Wi-Fi needs the proxy set for both.setManual()anddisable()write the host configuration, which is not interface-specific. setManual()replaces the bypass list. A call without the fifth argument stores an empty bypass list, so a device provisioned with BrightScript loseslocalhostand127.0.0.1and playback breaks. Pass the complete bypass list on every call.- Reboot after changing the proxy. File transfers pick up a new proxy on the next transfer, but the HTML application is given its proxy and bypass list once, when the widget is created, so the browser keeps the old settings until the device restarts.
Set the proxy and the bypass list in one step — either both in BrightScript or both in a single setManual() call — and reboot
afterwards. That is the most predictable way to provision a CoreApp device.
How the Supervisor uses the proxy
The Supervisor is a Node.js process, and Node.js does not pick up the device proxy on its own. signageOS reads the device network configuration and routes its own traffic accordingly — the management connection, configuration requests, content and firmware downloads, and its own upgrades.
Things worth knowing:
- Only HTTP proxies are supported. The proxy address must start with
http://. That refers to the connection to the proxy; traffic through it stays encrypted.https://proxy addresses are rejected. - Credentials are handled for you. Enter the username and password as-is, including characters such as
@,:or$. - Only HTTPS and WSS traffic goes through the proxy. Plain
http://andws://targets are always connected to directly, whatever the proxy and bypass configuration say. HTTPS and WSS are tunnelled through the proxy with HTTPCONNECT. - Changes made through the management API apply immediately. The Supervisor re-reads the configuration as soon as
setManual()ordisable()succeeds. A proxy changed outside the management API — with BrightScript, or from DWS — is picked up within about a minute. Connections that are already open keep the previous route until they reconnect, so reboot the device if you need the switch to be immediate. - Bypass entries are honoured, including exact hostnames, domain suffixes (
.internal.example.com), wildcards (*.internal.example.com), CIDR ranges (10.0.0.0/8),<local>for hostnames without a dot and*for everything — on top of the local addresses that are always direct.
Verifying the configuration
- Check what the device has stored, from an applet or a Custom Script:
await sos.management.proxy.getConnectedTo();
await sos.management.proxy.getBypassList();getConnectedTo()reports the address without credentials — the username and password are removed before the value leaves the device, sohttp://proxy-server.domain.com:83is the expected result even for a proxy that authenticates. - Confirm the device is online in Box. When device sends telemetry you should also see connected proxy on Device Info page.
- If you control the proxy, its access log is the most reliable check: you should see
CONNECTentries for the signageOS hosts shortly after the device boots.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Device offline after setting a proxy | The proxy is unreachable from the device's network, or the credentials are wrong |
| Content does not play, device otherwise online | localhost / 127.0.0.1 missing from the bypass list |
| Playback broke right after setting the proxy from the JS API or a Custom Script | The call omitted the bypass list, which replaced the existing one with an empty list — call setManual() again with localhost, 127.0.0.1 and your own local hosts |
| Bypass list is empty after setting the proxy | Same cause — setManual() writes the bypass list on every call, so it must always be passed in full |
| Downloads still fail from a local content server | On CoreApp the bypass list does not apply to file transfers; the proxy must be able to reach that server |
| Proxy appears to be ignored on a Supervisor device | The CoreApp build predates Supervisor proxy support — update to the latest CoreApp release (check the version in DWS) |
| Some Supervisor traffic never reaches the proxy | Only HTTPS and WSS are proxied; plain http:// targets always connect directly |
| Change did not take effect immediately | Existing connections keep the old route until they reconnect; reboot to force it |
For Supervisor-specific diagnostics, see BrightSign Supervisor Troubleshooting.
Correct proxy configuration is enforced from CoreApp/CloudControl 2.1.0. The bypass list argument of
setManual() and the getBypassList() method require CoreApp/CloudControl 2.6.0; on earlier versions the bypass list can only be set
with BrightScript. For any version older than 2.1.0, please reach out to our support team for a
technical guide.