DevOps & CI/CD

Integrate NGSRV into your deployment pipelines and infrastructure

Official Docker Images

NGSRV CLI is available as official Docker images with multi-architecture support:

Distroless (Recommended)

ngsrv/cli:latest
  • • Size: ~15-20 MB
  • • Security: Minimal attack surface
  • • Best for: Production

Alpine

ngsrv/cli:alpine
  • • Size: ~20-25 MB
  • • Includes: Shell, debugging tools
  • • Best for: Development, debugging

Multi-Architecture Support

Both images support linux/amd64, linux/arm64, and linux/arm/v7 - perfect for x86 servers, Apple Silicon, AWS Graviton, and Raspberry Pi.

Quick Start

docker pull ngsrv/cli:latest
docker run --rm -e NGSRV_API_TOKEN=your_token ngsrv/cli:latest http 3000

CI/CD Integration

Use NGSRV in your continuous integration pipelines for preview deployments and testing:

GitHub Actions

name: Preview Deployment
on: [pull_request]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Install dependencies
        run: npm install
      
      - name: Build application
        run: npm run build
      
      - name: Start server
        run: npm start &
      
      - name: Setup NGSRV
        run: |
          curl -fsSL https://get.ngsrv.com | bash
          export NGSRV_API_TOKEN=${{ secrets.NGSRV_TOKEN }}
          ngsrv http 3000 --domain pr-${{ github.event.number }} &
      
      - name: Run E2E tests
        run: npm run test:e2e
        env:
          BASE_URL: https://pr-${{ github.event.number }}.tnl.ngsrv.com
      
      - name: Comment PR
        uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.name,
              body: '🚀 Preview: https://pr-${{ github.event.number }}.tnl.ngsrv.com'
            })

GitLab CI

preview:
  stage: deploy
  script:
    - npm install
    - npm run build
    - npm start &
    - curl -fsSL https://get.ngsrv.com | bash
    - ngsrv http 3000 --domain mr-$CI_MERGE_REQUEST_IID &
    - echo "Preview URL: https://mr-$CI_MERGE_REQUEST_IID.tnl.ngsrv.com"
  environment:
    name: preview/mr-$CI_MERGE_REQUEST_IID
    url: https://mr-$CI_MERGE_REQUEST_IID.tnl.ngsrv.com
  only:
    - merge_requests

Kubernetes Integration

Expose services running in your Kubernetes cluster for external access:

Sidecar Container Pattern (Production)

Production-ready sidecar manifest. Uses the ngsrv run command (CLI v2.3.0+) which reads tunnel definitions from a ConfigMap, exposes /healthz, /readyz, and /metrics on port 9091, and emits structured JSON logs for Loki / Datadog / Cloud Logging.

apiVersion: v1
kind: Secret
metadata:
  name: ngsrv-credentials
type: Opaque
stringData:
  NGSRV_API_TOKEN: ngsrv_xxxxxxxxxxxxxxxxxxxx
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ngsrv-config
data:
  ngsrv.yml: |
    tunnels:
      - name: web
        port: 3000
        host: localhost
        subdomain: my-app
        # security_policies: ["ngsrv_ips_office"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 1
  selector: { matchLabels: { app: myapp } }
  template:
    metadata:
      labels: { app: myapp }
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9091"
        prometheus.io/path: "/metrics"
    spec:
      containers:
      - name: app
        image: myapp:latest
        ports: [{ containerPort: 3000 }]

      - name: ngsrv
        image: ngsrv/cli:2.3.0
        args:
          - run
          - --config
          - /etc/ngsrv/ngsrv.yml
          - --log-format
          - json
          - --ops-port
          - "9091"
        env:
          - name: NGSRV_API_TOKEN
            valueFrom:
              secretKeyRef: { name: ngsrv-credentials, key: NGSRV_API_TOKEN }
          - name: POD_NAME
            valueFrom: { fieldRef: { fieldPath: metadata.name } }
        ports:
          - { name: ops, containerPort: 9091 }
        livenessProbe:
          httpGet: { path: /healthz, port: ops }
          periodSeconds: 30
        readinessProbe:
          httpGet: { path: /readyz, port: ops }
          periodSeconds: 10
        resources:
          requests: { cpu: 50m, memory: 64Mi }
          limits:   { cpu: 500m, memory: 256Mi }
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          capabilities: { drop: ["ALL"] }
        volumeMounts:
          - { name: config, mountPath: /etc/ngsrv, readOnly: true }
      volumes:
        - name: config
          configMap: { name: ngsrv-config }

Why this layout works in production:

  • Sidecar shares the Pod network - localhost:3000 reaches the app container with zero extra plumbing.
  • livenessProbe / readinessProbe on /healthz and /readyz keep traffic away from Pods whose tunnel hasn't registered yet.
  • JSON logs get parsed cleanly by every cluster log aggregator (vs ANSI-coloured TUI output).
  • ConfigMap-driven - declare every tunnel for the Pod in one YAML file; one process runs them all.

Helm chart available

The same manifest is packaged as a Helm chart at cli/deploy/helm/ngsrv-sidecar/. Optional ServiceMonitor for kube-prometheus-stack is included.

kubectl create secret generic ngsrv-credentials \
  --from-literal=NGSRV_API_TOKEN=ngsrv_xxx

helm install web-tunnels ./cli/deploy/helm/ngsrv-sidecar \
  --set "config.tunnels[0].port=3000" \
  --set "config.tunnels[0].subdomain=my-app"

Docker Integration

Use NGSRV with Docker Compose for local development:

services:
  app:
    build: .
    expose:
      - "3000"
    environment:
      - NODE_ENV=development

  ngsrv:
    image: ngsrv/cli:latest
    environment:
      - NGSRV_API_TOKEN=${NGSRV_API_TOKEN}
    # --host points at the docker network service name "app"
    command: http 3000 --host app
    depends_on:
      - app

Start with: docker compose up. The CLI reads NGSRV_API_TOKEN from the environment when no ~/.ngsrv/tokens.json file is mounted (CLI v2.2.9+).

Cloud Platform Integration

Integrate NGSRV with major cloud platforms:

AWS (EC2, ECS, Lambda)

  • EC2: Install CLI on instance, expose internal services
  • ECS: Add as sidecar container in task definition
  • Lambda: Test locally before deployment with SAM/Serverless

Google Cloud (GCE, GKE, Cloud Run)

  • GCE: Expose Compute Engine instances without external IPs
  • GKE: Use sidecar pattern for service exposure
  • Cloud Run: Test locally before container deployment

Azure (VMs, AKS, Functions)

  • VMs: Quick external access without NSG configuration
  • AKS: Expose services for testing and debugging
  • Functions: Local testing with Azure Functions Core Tools

Security Best Practices

  • Use API tokens, not passwords

    Store tokens in CI/CD secrets, never commit them to code

  • Rotate tokens regularly

    Create separate tokens for each environment/pipeline

  • Use custom domains for production-like testing

    Configure custom domains in Dashboard → Domains

  • Monitor usage and logs

    Review tunnel activity in the Tunnels dashboard

  • Clean up temporary tunnels

    Tunnels automatically close when the CLI disconnects