Guide · Remote access · harborvps.com
Harbor has no built-in login. If the UI/API are reachable, anyone who can hit them can run SSH actions on your configured hosts. Use one of these operator recipes — Harbor does not implement these for you.
127.0.0.1:8787, UI 127.0.0.1:5173 (dev).
Binding outside loopback only warns at startup; you must still gate access.
| Recipe | Best when | Notes |
|---|---|---|
| SSH tunnel | You already SSH to the box | Recommended default — no public Harbor ports |
| IP allowlist | Stable home/office IP | IP changes lock you out |
| Tailscale / WG | Private access from devices | No public Harbor surface |
| CF Zero Trust | Browser login + MFA | Tunnel + Access; origin stays localhost |
| Proxy basic auth | Simple password on HTTPS | Weaker than Access / VPN |
Keep Harbor on loopback on the VPS. Reach it from your laptop through SSH.
ssh -N -L 5173:127.0.0.1:5173 -L 8787:127.0.0.1:8787 your-vps
Open http://127.0.0.1:5173 locally. Authorization = “can you SSH as the operator.”
Allow Harbor ports only from your public IP. Drop everyone else.
ufwsudo ufw default deny incoming sudo ufw allow OpenSSH sudo ufw allow from YOUR.PUBLIC.IP.HERE to any port 8787 proto tcp sudo ufw allow from YOUR.PUBLIC.IP.HERE to any port 5173 proto tcp sudo ufw enable sudo ufw status
Same idea in a cloud security group: source /32, never 0.0.0.0/0 on Harbor ports.
Home IPs change; shared NAT is a poor allowlist source. This is network-only — no MFA.
127.0.0.1 and use Serve / an SSH tunnel over the mesh.Access ≈ membership of your tailnet / WG peers (optionally Tailscale ACLs / SSO).
Expose Harbor without opening inbound ports: Tunnel connects out; Access enforces login (email OTP, Google/GitHub, IdP, device posture).
cloudflared on the VPS.127.0.0.1.harbor.example.com → http://127.0.0.1:5173 (and protect the API the same way if separate).8787 / 5173.# cloudflared ingress — illustrative; follow current Cloudflare docs
ingress:
- hostname: harbor.example.com
service: http://127.0.0.1:5173
- service: http_status:404
Point the UI at an Access-protected API origin. Cloudflare’s UI changes — treat this as the pattern.
TLS terminator on :443; Harbor stays on localhost. Caddy sketch:
harbor.example.com {
basicauth {
# caddy hash-password
operator JDJhJDEwJ...hashed...
}
reverse_proxy 127.0.0.1:5173
}
Prefer Access / Tailscale / SSH for anything serious. Protect UI and API if both are reachable.
HOST=0.0.0.0 and open Harbor ports to the world with no other controlapps/api/data/ (hosts, tokens, SQLite) to a public repo or image127.0.0.1 unless you have a deliberate publish path