7.5 KiB
Resources: public vs private
Pangolin has two kinds of resource. The names vary across the codebase, the UI, the API and blueprints, so learn the mapping:
| Public resource | Private resource | |
|---|---|---|
| Other names | proxy resource, resource |
site resource, client resource, siteResource |
| What it is | Exposed through Traefik on a domain/port, protected by Pangolin auth | Reachable only by Pangolin clients (Olm) over the tunnel |
| DB table | resources (resourceId, resourceGuid, niceId) |
siteResources (siteResourceId, niceId) |
Modes (mode) |
http, tcp, udp, ssh, rdp, vnc, inference |
host, cidr, http, ssh, inference, gateway |
| Backends | targets table (server/routers/target/) |
Fields on the site resource itself + siteNetworks/networks |
| Access join tables | roleResources, userResources, resourceWhitelist, policies |
roleSiteResources, userSiteResources, clientSiteResources |
| Labels | resourceLabels |
siteResourceLabels |
| AI | resourceAiProviders, resourceAiModels |
siteResourceAiProviders, siteResourceAiModels |
| Server router | server/routers/resource/ (+ server/private/routers/resource/) |
server/routers/siteResource/ |
| Access middleware | verifyResourceAccess / verifyApiKeyResourceAccess |
verifySiteResourceAccess / verifyApiKeySiteResourceAccess |
| Delete helper | server/lib/deleteResource.ts |
server/lib/deleteSiteResource.ts |
| Blueprint key | public-resources (legacy alias proxy-resources) |
private-resources (legacy alias client-resources) |
| Blueprint schema | PublicResourceSchema in server/lib/blueprints/types.ts |
PrivateResourceSchema in the same file |
| Blueprint apply | server/lib/blueprints/publicResources.ts → updatePublicResources |
server/lib/blueprints/privateResources.ts → updatePrivateResources |
| Blueprint export | buildPublicResourceBlueprintConfig in server/lib/blueprints/exportResourceBlueprint.ts |
buildPrivateResourceBlueprintConfig in the same file |
| Integration API path | /resource/... and /public-resource/... |
/site-resource/... and /private-resource/... |
| OpenAPI tags | PublicResource + PublicResourceLegacy |
PrivateResource + PrivateResourceLegacy |
| UI pages | src/app/[orgId]/settings/resources/public/ |
src/app/[orgId]/settings/resources/private/ |
| UI context | ResourceProvider / useResourceContext |
SiteResourceProvider / useSiteResourceContext, useSaveSiteResource |
| Traefik config | server/lib/traefik/getTraefikConfig.ts (+ private override) |
server/lib/traefik/siteResourceAlias.ts (cert placeholders for http-mode aliases) |
"Every resource" means both columns. When you add a capability to one kind, check whether the other needs it too.
Checklist: changing what a resource can be configured with
Use this whenever you touch createResource, updateResource,
createSiteResource or updateSiteResource (a new field, a renamed field, new
enum values, or a new mode). The blueprint must be able to do everything the API
can do.
-
DB: add the column to both
server/db/pg/schema/schema.tsandserver/db/sqlite/schema/schema.tsusing portable types (seedocs/database.md). UseprivateSchema.tsif the feature is enterprise-only. Don't write a migration script. If existing rows need values copied or generated, add them to the release's migration notes (server/setup/migrationNotes/<version>.md). -
API handlers: update the zod body schemas in
server/routers/resource/createResource.ts,updateResource.ts, orserver/routers/siteResource/createSiteResource.ts,updateSiteResource.ts
and the
get/listresponse types if the field is returned. -
Blueprint schema: add the field to
PublicResourceSchemaorPrivateResourceSchemainserver/lib/blueprints/types.ts. Blueprint keys are kebab-case (e.g."auth-daemon","estimated-time"). DB/API fields are camelCase. Enterprise-only blueprint fragments get a#dynamicschema with an empty OSS stub, likeserver/lib/blueprints/MaintenanceSchema.ts↔server/private/lib/blueprints/MaintenanceSchema.ts. -
Blueprint apply: map the blueprint field to the DB column in both the create and the update branches of
updatePublicResources(publicResources.ts) orupdatePrivateResources(privateResources.ts). Mirror any paywall or tier checks the API handler does (see howtierMatrix.maintenancePageis enforced there). -
Blueprint export: emit the field in
buildPublicResourceBlueprintConfigorbuildPrivateResourceBlueprintConfig(exportResourceBlueprint.ts) so a resource round-trips through export and apply. -
Docker labels: Newt docker labels (
pangolin.public-resources.*/pangolin.proxy-resources.*andpangolin.private-resources.*/pangolin.client-resources.*) are parsed byparseDockerContainers.ts/parseDotNotation.tsinto the same schema. They usually work once the schema is updated. Check them if the field is an array or object. -
Integration API: if you add a route, register it in
server/routers/integration.ts(or the private one) with both paths (see below), and add aregistry.registerPathper path with the right OpenAPI tag. -
UI: update the relevant tab page under
src/app/[orgId]/settings/resources/{public,private}/[niceId]/and the create page. All strings go inmessages/en-US.json. -
Traefik / Newt / Olm: if the field changes routing, update
server/lib/traefik/(public) or the Newt/Olm message builders inserver/routers/newt/andserver/routers/olm/(private).
Integration API aliases
Integration API resource routes always register the legacy path and the new alias in one array:
authenticated.put(
["/org/:orgId/resource", "/org/:orgId/public-resource"],
verifyApiKeyOrgAccess,
verifyLimits,
verifyApiKeyHasAction(ActionsEnum.createResource),
logActionAudit(ActionsEnum.createResource),
resource.createResource
);
authenticated.get(
["/site-resource/:siteResourceId", "/private-resource/:siteResourceId"],
verifyApiKeySiteResourceAccess,
verifyApiKeyHasAction(ActionsEnum.getSiteResource),
siteResource.getSiteResource
);
Mapping: resource(s) → public-resource(s), resource-policy/resource-policies
→ public-resource-policy/public-resource-policies, site-resource(s) →
private-resource(s).
The handler registers OpenAPI docs for both: the legacy path with
OpenAPITags.PublicResourceLegacy (or PrivateResourceLegacy) and the alias
with OpenAPITags.PublicResource (or PrivateResource). See
server/routers/resource/createResource.ts and
server/routers/siteResource/createSiteResource.ts.
The dashboard routes in server/routers/external.ts don't need the alias.
Related code
- Access checks:
server/auth/canUserAccessResource.ts,server/auth/canUserAccessSiteResource.ts,server/lib/canUserAccessResource.ts. - Client ↔ site resource access recomputation:
server/lib/rebuildClientAssociations.ts(call it after changing who can reach a site resource). - Resource policies (shared auth and rules for public resources):
server/routers/policy/,server/private/routers/policy/, blueprintpublic-policies→server/lib/blueprints/resourcePolicies.ts. - Applying blueprints:
server/lib/blueprints/applyBlueprint.ts, routes inserver/routers/blueprints/, UI insrc/app/[orgId]/settings/blueprints/.