Skip to main content
v5.32
operator
Last updated on

Remote access via reverse tunneling

info

Looking for general SSH access instructions? See the SSH access page.

In some deployments, the Charge Controller sits on a separate network — often behind a local Ethernet switch — with no way to establish direct access from the outside. This often hinders access to the Config UI and SSH, essential for troubleshooting and maintenance.

This guide explains how to establish remote access via a reverse tunnel. The tunnel is created from the Charge Controller itself and links back to your own Tunneling Server, enabling access through restrictive networks (e.g. NAT, CG-NAT, firewalls).

caution

Reverse tunneling should only be used as a fallback when every other option has been exhausted. It is not a reliable, long-term solution and comes with limitations.

1. Common connectivity challenges

Your Charge Controller may be remotely unreachable due to:

  • Multiple NAT layers: Cellular or router-based NAT, or both
  • No public IP address: Common with mobile internet providers
  • Firewall restrictions: Prevent incoming connections
  • Isolated sub-nets: Devices are isolated from office networks or VPNs

2. Tunneling feature overview

The Charge Controller has built-in reverse tunneling capabilities that allow it to establish an outbound connection to a publicly accessible Tunneling Server. This creates a secure tunnel that allows you to connect back to the Charge Controller through the Tunneling Server, bypassing NAT and firewall restrictions.

2.1. How it works

  1. The Charge Controller initiates an outbound SSH connection to your Tunneling Server
  2. This connection establishes a reverse tunnel that maps ports on your Tunneling Server to services on the Charge Controller
  3. You can then connect to these mapped ports on your Tunneling Server to access the Charge Controller
Reverse Tunneling connection between the maintenance engineer and the charge controller

2.2. Tunneling options

The Charge Controller has two scripts to enable tunneling:

Script
Tunnel Purpose
External Port on Tunneling Server
Internal Port on Controller
Service behind tunnel
#
custom_script1.sh
Enable SSH access
1111
22
SSH
#
custom_script2.sh
Enable Config UI access
1112
80
HTTP/Config UI
info
  • The ports are fixed and cannot be changed
  • Each script establishes a reverse SSH tunnel from the Charge Controller to the Tunneling Server
  • The tunneled service may be SSH or HTTP
  • SSH acts as the transport layer for both tunneling scripts

3. Firewall rules and needed open ports

The following must be true:

  • The Charge Controller can establish an outbound SSH connection (TCP 22) to the Tunneling Server
  • The Operator is able to reach the tunneled entry ports on the Tunneling Server
Location
Direction
Protocol
Port(s)
Needed for
#
Controller-side firewall / router
Outbound
TCP
22
Tunnel connection from Charge Controller to Tunneling Server
#
Tunneling Server firewall
Inbound
TCP
22
Accept inbound SSH connection from Charge Controller (reverse tunnel transport)
#
Tunneling Server firewall
Inbound
TCP
1111
Operator connects to this port of the Tunneling Server (forwarded to controller:22)
#
Tunneling Server firewall
Inbound
TCP
1112
Operator connects to this port of the Tunneling Server (forwarded to controller:80)
Reverse Tunneling firewall rules
tip
  • The Charge Controller initiates the reverse SSH tunnel by establishing an outbound TCP 22 connection to the Tunneling Server.
  • Once the tunnel is established, external access is provided via the Tunneling Server on TCP ports 1111 and 1112.

4. Activation

If your Charge Controller is connected to an OCPP Backend, you can trigger script execution remotely using the OCPP ChangeConfiguration.req command.

4.1. Requirements

Requirement
Description
#
Public Tunneling Server
Must be reachable from the internet and listening on port 22 (standard SSH port)
#
Authorized SSH key
Controller’s public key must be added to the Tunneling Server’s authorized_keys
#
Internet connectivity
Controller must be able to reach the Tunneling Server over the internet
#
OCPP backend
Controller must be actively connected to an OCPP backend
#
Trigger format
Use OCPP ChangeConfiguration.req with name and value
#
Fixed tunnel mappings
Port 1111 on the Tunneling Server is mapped to port 22 on the Charge Controller (for SSH access), port 1112 to port 80 (HTTP)
#
Input limitations
Only one string argument allowed (user@host) — no additional flags or parameters
#
No execution feedback
Tunnel command runs in the background; no direct confirmation is returned

4.2. Retrieve the SSH key and add it to your Tunneling Server

  1. The SSHClientKey key under the OCPP configuration (GetConfiguration) contains the public SSH key
  2. Add this key to your Tunneling Server’s authorized_keys file

4.3. Trigger the tunnel

info

How to trigger the tunnel depends on your OCPP Backend. Refer to the documentation of your OCPP Backend for more info.
Some allow you to put a value directly into the configuration key.
Others require you to send a ChangeConfiguration request.

Run a ChangeConfiguration request with the following body:

Payload example:

Request body type: JSON (raw)
{
"name": "INVOKECUSTOMSCRIPT1",
"value": "your-username@192.168.0.1"
}
tip

A ChangeRequest can be run through most OCPP Backends by changing the value of the configuration key inside the Backend dashboard.

Replace:

  • INVOKECUSTOMSCRIPT1 with INVOKECUSTOMSCRIPT2 to create a Config UI tunnel instead.
  • your-username@192.168.0.1 with your Tunneling Server details
info

Only one tunnel can be run at a time

5. Accessing the tunnel

Once established, you can reach the Charge Controller from your local machine through the external Tunneling Server:

SSH access

ssh -p 1111 your-username@your-tunneling-server.com

Config UI access

http://your-tunneling-server.com:1112

5.0.1. Limitations and considerations

  • Hardcoded port mappings

    • custom_script1.sh maps remote port 1111 to the Charge Controller’s port 22 (SSH)
    • custom_script2.sh maps remote port 1112 to port 80 (Config UI)
    • These values are fixed and can't be changed
    • This means your Tunneling Server needs to reserve ports 1111 and 1112 for tunneling
  • No result feedback through OCPP

    • Script success or failure isn't communicated back via ChangeConfiguration
    • You need to manually verify tunnel functionality (e.g. by attempting to connect to port 1111)
  • Reliance on correct DNS resolution

    • DNS may fail in cellular or captive network environments (NAT or CGNAT environments)
    • Using raw IP addresses is recommended to avoid silent failures but may raise security concerns

6. Troubleshooting

Once you've got direct access to the Charge Controller, you can either

a) Check the log in in the Config UI under Diagnostics > User Logs (put ocpp in the search field and click Apply) or
b) Check the log through SSH

If you encounter issues with the tunneling, here are some common problems and solutions:

6.1. Tunnel not created

  • Confirm the Charge Controller has internet access
  • Confirm the Tunneling Server is reachable and the public key is authorized
  • Confirm the value string matches username@host

6.2. Script not triggered

  • Ensure the Charge Controller is connected to the OCPP Backend
  • Check controller logs for execution messages
    • Do note that the OCPP Backend won't produce any logs related to the tunneling procedure

6.3. Tunnel drops intermittently

  • Some routers may close idle ports; use ServerAliveInterval on your Tunneling Server

7. Frequently asked questions

Question
Answer
#
Do I need an OCPP backend to use tunneling?
Yes
#
Can I change the port numbers used by the reverse tunnel?
No
#
Is the reverse tunnel secure?
Yes, the reverse tunnel uses industry-standard encryption and public key authentication. However, the security also depends on how well you secure your Tunneling Server and manage the Charge Controller's public key
#
Can I use the reverse tunnel for other services besides SSH and HTTP?
No
#
How does the tunnel handle network interruptions?
The connection needs to be reestablished manually after an interruption. There is no notification on an interrupted connection