docs/enterprise/deployment/kubernetes.mdx
Deploy Context7 On-Premise on Kubernetes using raw manifests. This guide assumes you have completed the On-Premise setup and have a valid license key.
kubectl configured for your clusterReadWriteOnce volumesContext7 Enterprise images are hosted on ghcr.io and require authentication. Create an image pull secret using your license key:
LICENSE_KEY="<your-license-key>"
# Get a registry token from Context7
TOKEN=$(curl -s -H "Authorization: Bearer $LICENSE_KEY" \
https://context7.com/api/v1/license/registry-token | jq -r '.token')
# Create the namespace and secrets
kubectl create namespace context7
kubectl create secret docker-registry context7-registry \
--namespace context7 \
--docker-server=ghcr.io \
--docker-username=x-access-token \
--docker-password="$TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic context7-config \
--namespace context7 \
--from-literal=LICENSE_KEY="$LICENSE_KEY" \
--dry-run=client -o yaml | kubectl apply -f -
Context7 Enterprise runs as a single-replica StatefulSet with persistent storage. The manifests below define the core resources: a StatefulSet for the application, a Service for internal routing, and an Ingress for external access.
Context7 uses SQLite and LanceDB for local storage, which require a persistent volume. This means it must run as a StatefulSet with a single replica since SQLite does not support concurrent writers.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: context7
namespace: context7
spec:
serviceName: context7
replicas: 1
selector:
matchLabels:
app: context7
template:
metadata:
labels:
app: context7
spec:
imagePullSecrets:
- name: context7-registry
terminationGracePeriodSeconds: 60
containers:
- name: context7
image: ghcr.io/context7/enterprise:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
name: http
env:
- name: LICENSE_KEY
valueFrom:
secretKeyRef:
name: context7-config
key: LICENSE_KEY
volumeMounts:
- name: data
mountPath: /data
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "4"
memory: "8Gi"
startupProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 12
livenessProbe:
httpGet:
path: /api/health
port: http
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /api/health
port: http
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeClaimTemplates:
- metadata:
name: data
spec:
# storageClassName: gp3 # Set this if your cluster has no default StorageClass
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
apiVersion: v1
kind: Service
metadata:
name: context7
namespace: context7
spec:
selector:
app: context7
ports:
- port: 3000
targetPort: http
protocol: TCP
name: http
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: context7
namespace: context7
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
tls:
- hosts:
- context7.internal.yourcompany.com
secretName: context7-tls
rules:
- host: context7.internal.yourcompany.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: context7
port:
number: 3000
Replace context7.internal.yourcompany.com with your actual hostname and context7-tls with your TLS secret.
After creating the namespace and secrets in the Registry Authentication step, apply the manifests:
kubectl apply -f statefulset.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
Verify the pod is running:
kubectl get pods -n context7
kubectl logs -n context7 context7-0
Once the pod is ready, open your Ingress hostname in a browser to complete the setup wizard.
Context7 requires outbound connectivity to the following:
| Destination | Purpose |
|---|---|
ghcr.io | Container image pulls (imagePullPolicy: Always) |
context7.com | License validation |
Your LLM provider (e.g. api.openai.com) | AI inference and embeddings |
github.com / gitlab.com | Repository cloning |
If you use NetworkPolicies, ensure egress to these endpoints is allowed:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: context7-egress
namespace: context7
spec:
podSelector:
matchLabels:
app: context7
policyTypes:
- Egress
egress:
- {} # Allow all egress (simplest)
For stricter policies, allow egress on port 443 to the specific domains listed above, and ensure egress to kube-dns on port 53 (UDP/TCP) is permitted for DNS resolution.
Pull the latest image and restart:
kubectl rollout restart statefulset/context7 -n context7
To pin a specific version:
kubectl set image statefulset/context7 \
context7=ghcr.io/context7/enterprise:1.2.0 \
-n context7
If your registry token has expired, refresh it before restarting:
LICENSE_KEY="<your-license-key>"
TOKEN=$(curl -s -H "Authorization: Bearer $LICENSE_KEY" \
https://context7.com/api/v1/license/registry-token | jq -r '.token')
kubectl create secret docker-registry context7-registry \
--namespace context7 \
--docker-server=ghcr.io \
--docker-username=x-access-token \
--docker-password="$TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
The /api/health endpoint returns structured JSON with license status, connectivity, and parsed repo count. Point your monitoring stack at it:
kubectl exec -n context7 context7-0 -- \
wget -qO- http://localhost:3000/api/health
Example response:
{
"status": "healthy",
"version": "1.0.0",
"setup": "complete",
"license": "configured",
"licenseInfo": {
"valid": true,
"teamSize": 10,
"expiresAt": "2026-06-01T00:00:00.000Z"
},
"repos_parsed": 5,
"uptime": 3600,
"connectivity": {
"llm": "configured",
"llm_provider": "openai",
"embedding": "configured",
"embedding_provider": "openai",
"github": "configured",
"gitlab": "not configured"
}
}
# Follow logs
kubectl logs -f -n context7 context7-0
# Check license and startup status
kubectl logs -n context7 context7-0 | head -20
Context7 validates your license key on startup. If the key is missing, invalid, or expired, the server exits immediately before the health endpoint is available. This means Kubernetes will report CrashLoopBackOff rather than a failed probe.
Check the logs first:
kubectl logs -n context7 context7-0
Look for [license] messages in the first few lines. Common causes:
LICENSE_KEY in the context7-config secretcontext7.com for license validationOnce deployed, point your MCP clients to your Ingress URL. See Connecting Your AI Client for client-specific instructions. Replace localhost:3000 with your Kubernetes Ingress hostname.