Private npm Registry (CI/CD Setup)
Private npm Registry — CI/CD Setup
Section titled “Private npm Registry — CI/CD Setup”The @forgejo-proxy/* packages are published to the private Verdaccio registry at
https://npm.registry.hochguertel.work/. This guide explains the authentication
architecture and how to configure CI/CD pipelines to publish and consume these packages.
Authentication Architecture
Section titled “Authentication Architecture”┌─────────────────────────────────────────────────────────────────┐│ npm.registry.hochguertel.work ││ ││ ┌─────────────────┐ ┌──────────────────────────────┐ ││ │ Web UI │ │ npm CLI / CI API requests │ ││ │ (browser) │ │ (/-/*, /pkg, PUT publish) │ ││ └────────┬────────┘ └──────────────┬───────────────┘ ││ │ │ ││ Authelia OIDC SSO BYPASS Authelia ││ (^/$ and ^/-/web) (all non-web paths in Traefik) ││ │ │ ││ └────────────┬───────────────────┘ ││ ▼ ││ ┌─────────────────┐ ││ │ Verdaccio │ ││ │ (registry-npm)│ ││ │ │ ││ │ Auth methods: │ ││ │ - OIDC (web) │ ││ │ - htpasswd │ ││ │ (CLI/CI) │ ││ └─────────────────┘ │└─────────────────────────────────────────────────────────────────┘Key insight: Traefik bypasses Authelia for all npm API paths (everything except the root
/ and /-/web/* paths). This means CI tools authenticate directly with Verdaccio’s
htpasswd plugin — no SSO required.
Service Account: forgejo-ci
Section titled “Service Account: forgejo-ci”A dedicated CI service account forgejo-ci is configured in both systems:
| System | Auth Method | Group |
|---|---|---|
| Verdaccio htpasswd | Basic Auth → JWT token | $authenticated |
| Authelia users_database.yml | argon2id password | developers |
The developers group membership in Authelia is needed for web UI access (optional for CI).
For CI/CD, only the Verdaccio htpasswd entry is required.
Package Scope Rules
Section titled “Package Scope Rules”The @forgejo-proxy/* scope in Verdaccio config:
'@forgejo-proxy/*': access: $all # Anyone can install (public read) publish: $authenticated # Any authenticated user can publish unpublish: $authenticated # No proxy — local-only packages (not forwarded to npmjs)This means:
- Install: No auth required (anyone can
npm install @forgejo-proxy/sdk) - Publish: Requires the Verdaccio JWT token (
NPM_REGISTRY_TOKENsecret)
CI/CD Configuration
Section titled “CI/CD Configuration”Forgejo Repository Secrets
Section titled “Forgejo Repository Secrets”The following secrets are configured on repos that publish or consume @forgejo-proxy/* packages:
| Secret | Value | Repos |
|---|---|---|
NPM_REGISTRY_TOKEN | Verdaccio JWT (30d expiry) | forgejo-proxy-api-spec, forgejo-proxy-cli |
NPM_REGISTRY_URL | https://npm.registry.hochguertel.work/ | Same repos |
.npmrc Configuration
Section titled “.npmrc Configuration”For publishing, add this to your CI workflow:
- name: Configure npm registry run: | echo "@forgejo-proxy:registry=https://npm.registry.hochguertel.work/" >> ~/.npmrc echo "//npm.registry.hochguertel.work/:_authToken=${NPM_REGISTRY_TOKEN}" >> ~/.npmrc env: NPM_REGISTRY_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}Full Publish Workflow Example
Section titled “Full Publish Workflow Example”name: Publish SDK
on: push: tags: ['v*']
jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2 with: bun-version: '1.3.0'
- name: Install dependencies run: bun install
- name: Configure npm registry run: | echo "@forgejo-proxy:registry=${{ secrets.NPM_REGISTRY_URL }}" >> ~/.npmrc echo "//${NPM_REGISTRY_URL#https://}:_authToken=${{ secrets.NPM_REGISTRY_TOKEN }}" >> ~/.npmrc env: NPM_REGISTRY_URL: ${{ secrets.NPM_REGISTRY_URL }}
- name: Build run: bun run build
- name: Publish run: npm publish --access public env: NPM_REGISTRY_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}Consuming Packages in Another Repo
Section titled “Consuming Packages in Another Repo”Add .npmrc to your project root:
@forgejo-proxy:registry=https://npm.registry.hochguertel.work/No token needed for installation — the @forgejo-proxy/* scope is publicly accessible.
Token Renewal
Section titled “Token Renewal”The JWT token expires after 30 days. To renew:
- Get the credentials from Bitwarden:
forgejo-ci npm registry (npm.registry.hochguertel.work) - Request a new token:
Terminal window NEW_TOKEN=$(curl -s -X PUT https://npm.registry.hochguertel.work/-/user/org.couchdb.user:forgejo-ci \-H "Content-Type: application/json" \-H "Authorization: Basic $(echo -n 'forgejo-ci:PASSWORD' | base64)" \-d '{"name":"forgejo-ci","password":"PASSWORD","type":"user"}' | python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])') - Update the Forgejo secrets on affected repos
- Update the Bitwarden entry with the new token and expiry date
Security Notes
Section titled “Security Notes”- The
forgejo-cihtpasswd password is stored in Bitwarden (vault:vault.hochguertel.work) - JWT tokens expire every 30 days (configured in Verdaccio
security.api.jwt.sign.expiresIn) - The htpasswd file on the VPS:
/opt/services/registries/npm/conf/htpasswd - Authelia config:
/opt/services/authelia/users_database.yml - All npm API paths bypass Authelia — this is by design for CLI/CI tooling compatibility