signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
215 lines (209 loc) • 30.2 kB
HTML
<html class="default" lang="en" data-base="./"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Security | Signal K</title><meta name="description" content="Documentation for Signal K"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css?cache=1783009712609"/><link rel="stylesheet" href="assets/highlight.css?cache=1783009712609"/><script defer src="assets/main.js?cache=1783009712609"></script><script async src="assets/icons.js?cache=1783009712609" id="tsd-icons-script"></script><script async src="assets/search.js?cache=1783009712609" id="tsd-search-script"></script><script async src="assets/navigation.js?cache=1783009712609" id="tsd-nav-script"></script><script async src="assets/hierarchy.js?cache=1783009712609" id="tsd-hierarchy-script"></script><link rel="stylesheet" href="assets/theme.css"/><script>if(window.self!==window.top){document.documentElement.classList.add('embedded')}</script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="index.html" class="title"><img class="title-logo" src="assets/logo.svg" alt="Signal K"/><svg class="title-home-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-label="Documentation home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg></a><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg><span class="visible@s">Search</span></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><div id="tsd-toolbar-links"><a href="https://discord.gg/uuZrwz4dCS" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"></path></svg></a><a href="https://github.com/SignalK/signalk-server" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg></a><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">Security</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="security" class="tsd-anchor-link">Security<a href="#security" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1>
<p>The umbrella term <em>Security</em> in Signal K server refers to the difference between running a server, that any one connected to the network can access and alter at will <strong>(unsecured)</strong> , and one with restrictions in place <strong>(secured)</strong>.</p>
<p>The available security options relate to:</p>
<ul>
<li><strong>authentication</strong>: Users and / or connecting devices having to provide a credential to gain access to the server <em>(e.g. username & password, access token, etc.)</em>.</li>
<li><strong>access control</strong>: Based on the authentication, access is granted to only specific Signal K data and server configuration.</li>
<li><strong>communications</strong>: Network traffic is encrypted and the identity of the server verified to protect against eavesdropping.</li>
<li><strong>network services</strong>: Control which of the server's services/interfaces are configured and active <em>(e.g. does it allow unsecured read/write over the network)</em>.</li>
</ul>
<h2 id="enabling-security" class="tsd-anchor-link">Enabling Security<a href="#enabling-security" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>When Signal K Server does not have security enabled, the <code>Login</code> option at the top right corner of the Admin UI will not be available.</p>
<p>Security can be enabled in several ways:</p>
<ol>
<li>
<p>Using the Admin UI, select <em>Security -> Users</em> and then:</p>
<ul>
<li>Click <strong>Add</strong></li>
<li>Enter a <strong>user id</strong></li>
<li>Enter a <strong>password</strong> and confirm it</li>
<li>In <strong>Permissions</strong> select <strong>Admin</strong></li>
<li>Click <strong>Apply</strong>.</li>
<li>Restart the Signal K Server.</li>
</ul>
</li>
<li>
<p>Starting the server with the <code>--securityenabled</code> command line option</p>
</li>
<li>
<p>Adding the following section in the settings file</p>
</li>
</ol>
<pre><code class="JSON"><span class="hl-4">"security"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"strategy"</span><span class="hl-0">: </span><span class="hl-4">"./tokensecurity"</span><span class="hl-0">,</span><br/><span class="hl-0"> }</span>
</code><button type="button">Copy</button></pre>
<p>When security is enabled, the next time you access the Admin UI it will prompt you to create an administrator account. During this setup you can optionally enable <a href="#allow-readonly-access">Allow Readonly Access</a> if you want unauthenticated users to be able to view data.</p>
<h2 id="security-settings" class="tsd-anchor-link">Security Settings<a href="#security-settings" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>After enabling security, the following settings are available in <strong>Security > Settings</strong>. They are stored in the <code>security.json</code> file in the server configuration directory, and can also be overridden with environment variables.</p>
<h3 id="allow-readonly-access" class="tsd-anchor-link">Allow Readonly Access<a href="#allow-readonly-access" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p><em>Default: <strong>off</strong> | Environment variable: <code>ALLOW_READONLY</code></em></p>
<p>When enabled, unauthenticated users can read Signal K data and use webapps (such as Instrument Panel or WilhelmSK) without logging in. They cannot modify data or access server configuration.</p>
<p>This is useful when you want guest crew to view navigation data or use instrument displays without creating individual accounts. However, it also exposes your data to anyone on the local network — and potentially on the public internet if your server is accessible externally (e.g. via port forwarding or when connected to marina WiFi).</p>
<h3 id="allow-new-user-registration" class="tsd-anchor-link">Allow New User Registration<a href="#allow-new-user-registration" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p><em>Default: <strong>on</strong> | Environment variable: <code>ALLOW_NEW_USER_REGISTRATION</code></em></p>
<p>When enabled, unauthenticated users can request an account by submitting their credentials to the server. The request enters a pending state and the admin is notified. The admin can then review and approve or deny the request in <strong>Security > Access Requests</strong>.</p>
<p>When disabled, only administrators can create user accounts manually via <strong>Security > Users</strong>. Self-registration attempts are rejected.</p>
<h3 id="allow-new-device-registration" class="tsd-anchor-link">Allow New Device Registration<a href="#allow-new-device-registration" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p><em>Default: <strong>on</strong> | Environment variable: <code>ALLOW_DEVICE_ACCESS_REQUESTS</code></em></p>
<p>When enabled, external devices (chart plotters, instrument displays, sensors) can request access tokens from the server. The device sends a request with its client identifier and description, and the admin is notified. The admin can approve or deny the request in <strong>Security > Access Requests</strong>, choosing which permission level to grant.</p>
<p>When disabled, devices cannot request access tokens. Administrators must pre-provision device tokens manually via <strong>Security > Devices</strong>.</p>
<h3 id="remember-me-timeout" class="tsd-anchor-link">Remember Me timeout<a href="#remember-me-timeout" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Controls how long the server keeps a user logged in when "Remember Me" is checked at login. Examples: <code>60s</code>, <code>1m</code>, <code>1h</code>, <code>1d</code>. The default is <code>NEVER</code> (session does not expire).</p>
<h2 id="disabling-security-lost-admin-credentials" class="tsd-anchor-link">Disabling Security / Lost Admin Credentials<a href="#disabling-security-lost-admin-credentials" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>In case the administrator user credentials are lost, removing the <code>security.json</code> file and restarting the server will restore access to the Admin UI.</p>
<h2 id="access-control" class="tsd-anchor-link">Access Control<a href="#access-control" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>Access control lists <em>(acls)</em> allow for fine grained access to specific data in Signal K. They specify the permissions assigned to users for resources within specifc contexts and are defined within the <code>security.json</code> file.</p>
<p>The following example defines acls for the self context allowing:</p>
<ol>
<li>
<p>Anyone to read the paths <code>"steering.*"</code>, <code>"navigation.*"</code>, <code>"name"</code>, <code>"design.aisShipType"</code> and grants the admin user permission to write (update) those paths.</p>
</li>
<li>
<p>The user <em>john</em> to read any data coming from the <code>actisense.35</code> $source.</p>
</li>
<li>
<p>For all other paths, only the admin user to read and no one can write.</p>
</li>
</ol>
<pre><code class="JSON"><span class="hl-0"> </span><span class="hl-4">"acls"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"context"</span><span class="hl-0">: </span><span class="hl-4">"vessels.self"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"resources"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"paths"</span><span class="hl-0">: [</span><span class="hl-4">"steering.*"</span><span class="hl-0">, </span><span class="hl-4">"navigation.*"</span><span class="hl-0">, </span><span class="hl-4">"name"</span><span class="hl-0">, </span><span class="hl-4">"design.aisShipType"</span><span class="hl-0">],</span><br/><span class="hl-0"> </span><span class="hl-3">"permissions"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"subject"</span><span class="hl-0">: </span><span class="hl-4">"any"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"permission"</span><span class="hl-0">: </span><span class="hl-4">"read"</span><br/><span class="hl-0"> },</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"subject"</span><span class="hl-0">: </span><span class="hl-4">"admin"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"permission"</span><span class="hl-0">: </span><span class="hl-4">"write"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</span><br/><span class="hl-0"> },</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"sources"</span><span class="hl-0">: [ </span><span class="hl-4">"actisense.35"</span><span class="hl-0"> ],</span><br/><span class="hl-0"> </span><span class="hl-3">"permissions"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"subject"</span><span class="hl-0">: </span><span class="hl-4">"john"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"permission"</span><span class="hl-0">: </span><span class="hl-4">"read"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</span><br/><span class="hl-0"> },</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"paths"</span><span class="hl-0">: [</span><span class="hl-4">"*"</span><span class="hl-0">],</span><br/><span class="hl-0"> </span><span class="hl-3">"permissions"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"subject"</span><span class="hl-0">: </span><span class="hl-4">"admin"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"permission"</span><span class="hl-0">: </span><span class="hl-4">"read"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</span>
</code><button type="button">Copy</button></pre>
<p><em>Note: If there is no match is found for a specific path in the acl list, then permission will be denied to that path!</em></p>
<h2 id="active-network-services" class="tsd-anchor-link">Active network services<a href="#active-network-services" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>Signal K Server's main network services are:</p>
<ul>
<li>The <em>primary Signal K http / WebSocket interface</em>, with options to use TLS encryption and authentication <em>(read/write)</em></li>
<li><em>NMEA0183 data over TCP</em> on port 10110 <em>(read only)</em></li>
<li><em>Signal K over TCP</em> on port 8375 <em>(read/write)</em></li>
</ul>
<p>In addition the user may configure any number of TCP, UDP and Websocket connections, some of which allow write access to the server.</p>
<p>The security implication of these connections is that with no security options turned on <em>devices connected to the network will have both read and write access to practically all of its data and settings</em>.</p>
<p>People often dismiss local network access by saying that their boat's local network is secure enough. But one very common scenario is connecting your Signal K server <em>(e.g. a Raspberry Pi)</em> to a marina wifi.
Many wifi networks allow communication between all connected computers, so your Signal K server will be advertising its services over MDNS to all other connected devices.</p>
<p>So in the case that your server has a manually configured connection for <em>NMEA0183 over UDP</em>, NMEA0183 data broadcast by other devices will be received and written into your SIgnal K data.</p>
<p>NMEA0183 connections over TCP and UDP are inherently unsafe. There are no options for authentication and / or secure communication. In comparison Signal K over TLS and HTTP / WebSockets can provide secure, authenticated read and write access to your data.</p>
<h2 id="security-headers" class="tsd-anchor-link">Security Headers<a href="#security-headers" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>Signal K Server uses the <code>helmet</code> middleware to set security-related HTTP headers:</p>
<table>
<thead>
<tr>
<th>Header</th>
<th>Value</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td>X-Content-Type-Options</td>
<td>nosniff</td>
<td>Prevents MIME type sniffing attacks</td>
</tr>
<tr>
<td>X-Frame-Options</td>
<td>SAMEORIGIN</td>
<td>Prevents clickjacking (allows same-origin iframes)</td>
</tr>
<tr>
<td>X-DNS-Prefetch-Control</td>
<td>off</td>
<td>Privacy protection</td>
</tr>
<tr>
<td>X-Download-Options</td>
<td>noopen</td>
<td>Prevents IE from executing downloads</td>
</tr>
<tr>
<td>X-Permitted-Cross-Domain-Policies</td>
<td>none</td>
<td>Blocks Flash/PDF cross-domain access</td>
</tr>
<tr>
<td>Referrer-Policy</td>
<td>no-referrer</td>
<td>Privacy protection</td>
</tr>
<tr>
<td>Strict-Transport-Security</td>
<td>max-age=15552000</td>
<td>Forces HTTPS (only sent on HTTPS connections)</td>
</tr>
</tbody>
</table>
<h3 id="intentionally-disabled" class="tsd-anchor-link">Intentionally Disabled<a href="#intentionally-disabled" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>The following helmet features are disabled to maintain compatibility with the SignalK ecosystem:</p>
<ul>
<li><strong>Content-Security-Policy</strong>: Would prevent webapps (Freeboard, Instrumentpanel) from loading external resources like map tiles and CDN scripts</li>
<li><strong>Cross-Origin-Embedder-Policy</strong>: Would prevent chart plotters from embedding SignalK data</li>
<li><strong>Cross-Origin-Resource-Policy</strong>: Would prevent legitimate cross-origin API access from instruments and apps</li>
</ul>
<h2 id="reverse-proxy-configuration-trust-proxy" class="tsd-anchor-link">Reverse Proxy Configuration (Trust Proxy)<a href="#reverse-proxy-configuration-trust-proxy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>When running Signal K Server behind a reverse proxy (e.g., nginx, Apache, Traefik), the server needs to be configured to trust the <code>X-Forwarded-For</code> header to correctly identify client IP addresses.</p>
<h3 id="why-enable-trust-proxy" class="tsd-anchor-link">Why Enable Trust Proxy?<a href="#why-enable-trust-proxy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Without this setting, when behind a reverse proxy:</p>
<ul>
<li>All requests appear to come from the proxy's IP (e.g., <code>127.0.0.1</code>)</li>
<li>Rate limiting becomes ineffective (limits apply to proxy, not individual clients)</li>
<li>Access logs show proxy IP instead of real client IP</li>
</ul>
<p>When <code>trustProxy</code> is enabled, Signal K uses the <code>X-Forwarded-For</code> header (set by your proxy) to identify the real client IP address.</p>
<h3 id="configuration" class="tsd-anchor-link">Configuration<a href="#configuration" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>The <code>trustProxy</code> setting can be enabled in the Admin UI under <strong>Server Settings > Options > trustProxy</strong>.</p>
<p>For most setups behind a local reverse proxy, simply enabling <code>trustProxy: true</code> in the Admin UI is sufficient.</p>
<p>For advanced configurations (specific proxy IPs, hop counts), edit <code>settings.json</code> directly:</p>
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">"settings"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"trustProxy"</span><span class="hl-0">: </span><span class="hl-4">"127.0.0.1"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<p>The <code>trustProxy</code> setting accepts the following values:</p>
<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>true</code></td>
<td>Trust all proxies (use with caution)</td>
</tr>
<tr>
<td><code>false</code></td>
<td>Don't trust any proxy (default)</td>
</tr>
<tr>
<td><code>"loopback"</code></td>
<td>Trust loopback addresses (127.0.0.1, ::1)</td>
</tr>
<tr>
<td><code>"linklocal"</code></td>
<td>Trust link-local addresses</td>
</tr>
<tr>
<td><code>"uniquelocal"</code></td>
<td>Trust unique local addresses</td>
</tr>
<tr>
<td>Number</td>
<td>Trust the first N proxies</td>
</tr>
<tr>
<td>IP/CIDR</td>
<td>Trust specific proxy addresses (e.g., <code>"192.168.1.1"</code> or <code>"10.0.0.0/8"</code>)</td>
</tr>
</tbody>
</table>
<h3 id="example-nginx-reverse-proxy" class="tsd-anchor-link">Example: nginx Reverse Proxy<a href="#example-nginx-reverse-proxy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>When using nginx as a reverse proxy, configure it to pass the client IP:</p>
<pre><code class="nginx"><span class="hl-1">location</span><span class="hl-0"> </span><span class="hl-5">/ </span><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-1"> proxy_pass </span><span class="hl-0">http://localhost:3000;</span><br/><span class="hl-0"> </span><span class="hl-1"> proxy_set_header </span><span class="hl-0">X-Forwarded-For $remote_addr;</span><br/><span class="hl-0"> </span><span class="hl-1"> proxy_set_header </span><span class="hl-0">X-Forwarded-Proto $scheme;</span><br/><span class="hl-0"> </span><span class="hl-1"> proxy_set_header </span><span class="hl-0">Host $host;</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<p>And set <code>trustProxy</code> to trust only the nginx server:</p>
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">"settings"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"trustProxy"</span><span class="hl-0">: </span><span class="hl-4">"127.0.0.1"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="security-considerations" class="tsd-anchor-link">Security Considerations<a href="#security-considerations" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
<ul>
<li>Only enable <code>trustProxy</code> if you are actually running behind a reverse proxy</li>
<li>Configure the value to trust only your specific proxy IP address when possible</li>
<li>Using <code>trustProxy: true</code> trusts all proxies, which could allow IP spoofing if your server is directly accessible</li>
</ul>
<h2 id="openid-connect-oidc-authentication" class="tsd-anchor-link">OpenID Connect (OIDC) Authentication<a href="#openid-connect-oidc-authentication" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>If you run multiple services alongside Signal K (such as Grafana, Node-RED, or others), managing separate user accounts and passwords for each becomes tedious and error-prone. OpenID Connect (OIDC) solves this by letting users authenticate once with a central identity provider and access all connected services.</p>
<p>For configuration and setup, see the <a href="Security/OIDC_Authentication.html">OIDC Authentication Guide</a>.</p>
</div></div><div class="col-sidebar"><div class="page-menu"><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#enabling-security"><span>Enabling <wbr/>Security</span></a><a href="#security-settings"><span>Security <wbr/>Settings</span></a><ul><li><a href="#allow-readonly-access"><span>Allow <wbr/>Readonly <wbr/>Access</span></a></li><li><a href="#allow-new-user-registration"><span>Allow <wbr/>New <wbr/>User <wbr/>Registration</span></a></li><li><a href="#allow-new-device-registration"><span>Allow <wbr/>New <wbr/>Device <wbr/>Registration</span></a></li><li><a href="#remember-me-timeout"><span>Remember <wbr/>Me timeout</span></a></li></ul><a href="#disabling-security-lost-admin-credentials"><span>Disabling <wbr/>Security / <wbr/>Lost <wbr/>Admin <wbr/>Credentials</span></a><a href="#access-control"><span>Access <wbr/>Control</span></a><a href="#active-network-services"><span>Active network services</span></a><a href="#security-headers"><span>Security <wbr/>Headers</span></a><ul><li><a href="#intentionally-disabled"><span>Intentionally <wbr/>Disabled</span></a></li></ul><a href="#reverse-proxy-configuration-trust-proxy"><span>Reverse <wbr/>Proxy <wbr/>Configuration (<wbr/>Trust <wbr/>Proxy)</span></a><ul><li><a href="#why-enable-trust-proxy"><span>Why <wbr/>Enable <wbr/>Trust <wbr/>Proxy?</span></a></li><li><a href="#configuration"><span>Configuration</span></a></li><li><a href="#example-nginx-reverse-proxy"><span>Example: nginx <wbr/>Reverse <wbr/>Proxy</span></a></li><li><a href="#security-considerations"><span>Security <wbr/>Considerations</span></a></li></ul><a href="#openid-connect-oidc-authentication"><span>Open<wbr/>ID <wbr/>Connect (<wbr/>OIDC) <wbr/>Authentication</span></a></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">Signal K</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>