Hi everyone,
I maintain a Pritunl setup (self-hosted, behind nginx as reverse proxy) and would like feedback from the community on whether this architecture is sound / best practice, or whether I’ve introduced unnecessary complexity or security risk.
Background
We run 3 independent Pritunl instances (separate DB/session per instance):
- Instance 1 – main VPN for employees, auth exclusively via SAML (Azure AD / Entra ID), used both by internal users (pulling profiles, docs) and external home-office users (VPN connection from outside). No RADIUS here — SAML is the intended auth method for this instance.
- Instance 2 – supports SAML (used only for profile retrieval, exclusively through an internally-resolved domain) in addition to RADIUS. This instance only exists because Pritunl doesn’t natively support multiple auth methods at once. RADIUS is needed here because of AlwaysOn VPN — the goal is to eventually replace the existing user tunnel with it. The SAML+RADIUS combination was solved via Pritunl’s plugin system. I wasn’t able to get it working via plugin in a way where specific servers/organizations use only RADIUS while others use only SAML.
- Instance 3 – fully separate, plain RADIUS server with classic MFA. The RADIUS server was already in use for other purposes, so we kept using it here — we’d actually prefer SAML for this one too, but OpenVPN itself doesn’t support SAML, and Pritunl currently has no native app for Android/iOS.
Domain structure (nginx, one server with multiple server_name blocks)
All three domains per instance ultimately proxy to the same backend instance (10.77.4.10:8443 in this example, for Instance 1), but with different location blocks / sub_filter rewrites depending on the target audience. All three instances share connect.corpvpn.example as the common public domain.
Instance 1
manage.corpvpn.example– access to the Pritunl admin UIportal.corpvpn.example– “user domain”: pulling profiles, docs page, customized login screen (native username/password fields stripped viasub_filter, only SAML login shown)connect.corpvpn.example(public) – serves actual VPN client operation for home-office users; also configured as the SSO Domain in Pritunl (i.e. the domain the SAML ACS callback points back to)
Instance 2
site2-manage.corpvpn.example(admin)site2-portal.corpvpn.example(portal/profiles)- public:
connect.corpvpn.example
Instance 3
mobile-manage.corpvpn.example(admin)mobile-portal.corpvpn.example(portal)- public:
connect.corpvpn.example
Redirect logic between domains
connect.corpvpn.example(public/SSO) → key/profile paths get 302-redirected toportal.corpvpn.example, since actual profile retrieval should happen there with the customized UIportal.corpvpn.example→ paths used for VPN client communication get 302-redirected back toconnect.corpvpn.example- the SAML callback path is proxied (not redirected!) on both domains, since a 301/302 on a SAML POST request would drop the body
Open questions for the community
- Does this setup make sense overall, or do you see fundamental issues with the architecture?
- Does the domain split make sense?
- What are generally considered best practices for running Pritunl?
- What are best practices for reverse proxy setup, combining SAML/RADIUS, multi-instance operation, etc.?
Thanks in advance for any input!