Your OCPI implementation runs on http://localhost:8000, or on a machine inside a VPC
that only your own network can reach. The tester is hosted, and it calls your endpoint
server to server. It cannot reach a laptop.
This is the normal state of a half-built integration, not a mistake you made. The fix that
works today is a tunnel: a small program you run next to your service that gives it a
temporary public HTTPS URL. You then use that URL as the base URL of a connection, exactly
as you would a partner’s.
What we do not ask you for
- No inbound firewall rule.
- No public hostname of your own.
- No TLS certificate on your side. The tunnel terminates HTTPS for you.
Your service keeps listening on plain HTTP on localhost. Nothing about it changes.
Start a tunnel
Both of these give you a random HTTPS URL and print it in the terminal. Pick one. Replace
8000 with the port your OCPI service listens on.
cloudflared
It prints a line with a https://<random-words>.trycloudflare.com URL. That is your
public base URL. No account is needed for this kind of quick tunnel.
ngrok
It prints a Forwarding line with a https://<random>.ngrok-free.app URL. That is your
public base URL. ngrok needs a free account for the authtoken, and it needs it only once
per machine.
Leave the tunnel running for as long as you are testing. Both tools issue a new random
URL every time you restart them, so a connection you created before a restart points at a
URL that no longer exists. That is expected and it is a one-field fix: see
When the tunnel URL changes.
Check it from outside your machine
Before you create a connection, prove the tunnel reaches your service:
The tr -d '\n' is not decoration. GNU coreutils base64 wraps its output every 76 characters,
so a token A longer than 57 bytes comes back with a newline in the middle and the header you send
is not the header you meant. It costs nothing on macOS, which does not wrap.
From OCPI 2.2 onwards the credentials token is Base64 encoded in the Authorization header, and
that is what we send, so testing with the encoded form is testing what will actually arrive. On
2.1.1 the token goes raw instead: -H "Authorization: Token <your token A>".
Note the two URLs on this page and the segment between them. You curl
https://<your-tunnel-host>/ocpi/versions, because that is the endpoint that answers with your
version list. You register https://<your-tunnel-host>/ocpi, because partnerBaseUrl is the URL
that endpoint hangs off, and we add /versions ourselves. Registering the one you curled asks your
own service for /ocpi/versions/versions.
If that answers, we can reach you too. If it does not, fix it here rather than in a run
report.
The part that costs people an afternoon
The tunnel host has to be the base URL you register and the host your own responses
advertise.
OCPI is a discovery protocol. Our client reads your /versions response, follows the
url it finds there to your version details, and follows those endpoints URLs to every
module. If your service builds those URLs from its local configuration, it will hand back
http://localhost:8000/ocpi/2.2.1/cdrs. We refuse to call that. A loopback or private
address is blocked before the request leaves us, so nothing is sent anywhere.
You will see this in the report, on the check that tried to use the URL:
That line is our refusal, not an answer from your service. It means you advertised a URL only
your own machine can reach, not that an HTTP call failed.
Where it lands is simply the first advertised URL we cannot call. Registration reads your
/versions, follows the url for the version you chose, and then posts to the credentials
endpoint listed there:
- If the
url in your /versions response is local, registration stops at the version details
step. This is the usual case, because one base setting normally feeds everything.
- If only the endpoint URLs in your version details are local, registration stops at the
credentials step.
- If only some module endpoints are local, registration finishes and those modules fail.
So set whatever your service uses as its public base URL (an environment variable in most
implementations) to the tunnel host before you start it, and confirm it with the curl
above. Every URL in the response should name the tunnel host.
Point a connection at it
From here nothing is special. Create the connection with the tunnel URL as
partnerBaseUrl and register it, the same as any partner:
Connect a partner endpoint covers the fields, the registration
handshake, and the version choice. Everything on that page applies here.
When the tunnel URL changes
Restart the tunnel and you get a new host. The connection you registered still holds the token
their system issued you, and the peer behind the tunnel has not changed at all: only the address
it answers on has. So you move the connection rather than rebuilding it.
On the Endpoints tab, press the pencil beside the base URL, paste the new one, and press
Change address. From the API:
The connection keeps its id, both tokens and its own past reports. Runs it inherited from an
earlier delete-and-re-register cycle usually follow it too, and the connection says so if they did
not. It drops to pending while we read your versions endpoint at the new address, and returns to
registered when that answers. If it does not answer, the connection stays pending at the
address you gave and says so, so you can verify it to try that address again or correct it.
Two things it will not do. It refuses while a run is still working against that endpoint, because
the run re-reads the connection as it goes. And it is capped at five changes a minute per account.
Do not reach for Update credentials here. That is the OCPI credentials PUT, and it sends to
the address we currently hold, which is the one that just went away. It is the right verb for
rotating a token at an address that still works, and the wrong one for an address that moved.
What this costs you
While the tunnel is up, your service is on the public internet, and anyone who has the
URL can reach it. There is no way around that: a tunnel works by making your service
reachable, and reachable means reachable by whoever holds the address.
The mitigations that actually exist:
- The URL is random and temporary. Nobody can guess
https://<random-words>.trycloudflare.com, and it stops working when you stop the
tunnel. This is real protection against strangers, and no protection at all against
anyone you sent the URL to.
- Our requests carry the token you configured, and nothing else about the tunnel
changes your authentication. If your service rejects requests without a valid OCPI
token, it still rejects them through the tunnel. This is your actual access control. If
your service does not check the token yet, the tunnel is the wrong time to find that out.
- Stop the tunnel when the run finishes. The exposure lasts exactly as long as the
process does. Stopping it costs you nothing except a new URL next time.
- Use throwaway data. A development database with invented CDRs and test tokens, never
a copy of production.
The login features these tools offer for protecting a URL (ngrok’s OAuth, Cloudflare
Access) put a browser sign-in in front of your service. Our requests are not a browser
and cannot sign in, so turning those on will block us along with everyone else. Treat
your own OCPI token check as the control that matters, and keep the tunnel window short.
If none of that is acceptable to you, use the connector instead. It
never puts your service on the internet.
Speed
A conformance run is sequential and small. Each request crosses the internet twice more
than it otherwise would, which adds tens of milliseconds per request and changes no
verdict. A tunnel is fine for conformance.
A load run is different. It measures the tunnel as much as it measures you, so the numbers
it produces are not about your service. Do not size anything from a load run over a tunnel.
If exposing it is not acceptable
Everything above puts your service on the public internet for as long as the tunnel runs. If
that is not something you can do, the connector is the other way:
a small binary beside your service that dials out to us, so nothing of yours is ever reachable
from the internet. It is part of a paid plan.
Next
- Connect a partner endpoint to create and register the
connection.
- Run a conformance suite against it.
- When your tunnel hands you a new URL, change the address
rather than starting over.