Exposing Web Services with frp
Inbound connections to compute nodes are not supported, so you cannot directly publish a listening port from a job to the internet. If you need to access a web service running inside a job (e.g. JupyterLab), you can use frp (Fast Reverse Proxy).
With this approach, the frpc client runs inside your Slurm job and establishes an outbound connection to a proxy server (frps).
The proxy server then exposes your local HTTP service under a public HTTPS URL.
Note
This is an experimental service. Ask hpc-support@dkf.hu for: the proxy server address/port, an authentication token, and the allowed domain(s).
Download frpc (client)
The upstream project publishes binaries on GitHub Releases.
Latest release page (always redirects to the newest version): https://github.com/fatedier/frp/releases/latest
Because the release assets are versioned (for example frp_<VERSION>_linux_amd64.tar.gz), there is no single, permanent URL that always
downloads “the latest tarball” without first resolving the current version. For automation, resolve the latest asset URL via the GitHub API:
# Download the latest Linux x86_64 client tarball (requires: curl, jq)
url="$(curl -fsSL https://api.github.com/repos/fatedier/frp/releases/latest \
| jq -r '.assets[] | select(.name | test("linux_amd64\\.tar\\.gz$")) | .browser_download_url' \
| head -n1)"
curl -fL -O "$url"
tar -xzf frp_*_linux_amd64.tar.gz
cd frp_*_linux_amd64
chmod +x frpc
Example frpc.toml configuration (HTTP)
Create a configuration file (TOML format), for example frpc.toml:
We recommend enabling HTTP Basic Authentication on the proxy by setting httpUser and httpPassword for the HTTP proxy.
serverAddr = "<FRPS_HOST_OR_IP>"
serverPort = 7000
auth.method = "token"
auth.token = "<FRP_TOKEN>"
[[proxies]]
name = "my-jupyter"
type = "http"
localIP = "127.0.0.1"
localPort = 8888
# Optional (recommended): protect access with HTTP Basic Auth
httpUser = "<HTTP_USER>"
httpPassword = "<HTTP_PASSWORD>"
# Choose a unique subdomain
subdomain = "<YOUR_SUBDOMAIN>"
# Domain suffix provided by DKF (example)
customDomains = ["guest.komondor.hinfra.hu"]
# Optional: basic health check to avoid routing to a dead service
healthCheck.type = "http"
healthCheck.path = "/"
healthCheck.intervalSeconds = 10
healthCheck.maxFailed = 3
healthCheck.timeoutSeconds = 3
healthCheck.httpHeaders = [
{ name = "x-from-where", value = "frp" }
]
After starting frpc with this config, the service is typically available at:
https://<YOUR_SUBDOMAIN>.guest.komondor.hinfra.hu/
Slurm example: publish a Jupyter notebook from a job
The key idea is to start both:
your local web service (listening on
127.0.0.1:<PORT>inside the allocated node), andfrpc(routing HTTP traffic from the proxy to that local port)
in the same Slurm job allocation.
Example frpc.sbatch:
#!/bin/bash
#SBATCH --partition=cpu
#SBATCH --cpus-per-task=16
#SBATCH --mem-per-cpu=2000
#SBATCH --account=<ACCOUNT>
#SBATCH --job-name=frpc
#SBATCH --time=01:00:00
#SBATCH --output=slurm-%j.out
set -euo pipefail
# Start frpc client (keep token/config in a protected location)
./frpc --config ./frpc.toml &
frpc_pid=$!
trap 'kill ${frpc_pid} 2>/dev/null || true' EXIT
# Start a local web service on the same node.
# Example: Jupyter notebook from a container.
module load singularity
singularity run --writable-tmpfs docker://jupyter/datascience-notebook \
start-notebook.py --IdentityProvider.token="<JUPYTER_TOKEN>"
Troubleshooting
Check the Slurm output (
slurm-%j.out) forfrpclogs and for the web service startup messages.Verify locally on the compute node that the service responds (example):
curl -I http://127.0.0.1:8888/.If you enabled health checks, ensure the
healthCheck.pathreturns a 2xx status code.If the public URL loads but notebooks fail to connect, ensure the service supports WebSockets (JupyterLab does) and that it is published via an HTTP proxy (not a raw TCP proxy).
Security notes
Treat the FRP auth token as a secret. Do not commit it into Git repositories.
Consider enabling HTTP Basic Auth in the proxy config (
httpUser/httpPassword) in addition to your application’s own authentication.Protect your application as well (e.g. use a strong Jupyter token) because it becomes internet-accessible.
Stop the job when you no longer need the service; the URL should be considered public for the duration of the job.