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 3000CI/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_requestsKubernetes 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:3000reaches the app container with zero extra plumbing. - livenessProbe / readinessProbe on
/healthzand/readyzkeep 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:
- appStart 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