1. Pengenalan Ingress
Ingress adalah resource Kubernetes yang mengatur akses eksternal ke service di dalam cluster â biasanya melalui HTTP dan HTTPS. Ingress memungkinkan Anda mengatur routing berdasarkan host name, URL path, dan konfigurasi TLS, sehingga Anda bisa mengakses beberapa aplikasi melalui satu LoadBalancer.
Tanpa Ingress, setiap service yang perlu diakses dari luar cluster harus menggunakan tipe LoadBalancer atau NodePort, yang berarti setiap service mendapatkan IP publik atau port sendiri. Dengan Ingress, Anda cukup satu LoadBalancer saja untuk mengelola ratusan service sekaligus.
Apa itu Ingress Controller?
Penting untuk dipahami bahwa resource Ingress hanyalah "aturan" â bukan sesuatu yang berjalan sendiri. Agar Ingress berfungsi, Anda membutuhkan Ingress Controller â software yang membaca resource Ingress dan mengkonfigurasikannya sebagai reverse proxy. Beberapa pilihan populer:
| Ingress Controller | Keunggulan | Best For |
|---|---|---|
| NGINX Ingress | Populer, stabil, documentation lengkap | Kebanyakan use case |
| Traefik | Auto-discovery, dashboard built-in | Microservices, dynamic config |
| HAProxy | High-performance, TCP/UDP support | High-traffic production |
| Kong | API Gateway features, plugin ecosystem | API management |
| Istio Gateway | Service mesh integration | Zero-trust security |
| Envoy (Contour) | gRPC support, high performance | gRPC-heavy workloads |
| AWS ALB Controller | Native AWS ALB integration | AWS EKS workloads |
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â KUBERNETES INGRESS ARCHITECTURE â â â â Internet â â â â â âŧ â â âââââââââââââââââââ â â â LoadBalancer â (Cloud LB / MetalLB) â â â (External IP) â â â ââââââââââŦâââââââââ â â â â â âŧ â â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â â â INGRESS CONTROLLER POD â â â â (NGINX / Traefik / HAProxy) â â â â â â â â ââââââââââââââââââââââââââââââââââââââââââââââââââ â â â â â Rules dari Ingress Resource: â â â â â â - app.example.com/ â app-service:80 â â â â â â - app.example.com/api â api-service:3000 â â â â â â - app.example.com/auth â auth-service:8080 â â â â â ââââââââââââââââââââââââââââââââââââââââââââââââââ â â â ââââââââââââŦâââââââââââââââŦâââââââââââââââŦââââââââââââââ â â â â â â â âŧ âŧ âŧ â â ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ â â â app-service â â api-service â â auth-service â â â â ClusterIP â â ClusterIP â â ClusterIP â â â ââââââââŦââââââââ ââââââââŦââââââââ ââââââââŦââââââââ â â âŧ âŧ âŧ â â ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ â â â App Pods â â API Pods â â Auth Pods â â â ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
2. Ingress vs Service LoadBalancer
Memahami perbedaan antara Service LoadBalancer dan Ingress sangat penting untuk memilih arsitektur yang tepat untuk aplikasi Anda.
Service LoadBalancer
Ketika Anda membuat Service dengan tipe LoadBalancer, Kubernetes akan meminta cloud provider untuk membuat load balancer ekstern untuk setiap service. Setiap service mendapatkan IP publik sendiri.
Perbandingan Detail
| Aspek | Service LoadBalancer | Ingress |
|---|---|---|
| IP Publik | Satu IP per service | Satu IP untuk semua service |
| Biaya Cloud | Tinggi (satu LB per service) | Rendah (satu LB untuk semua) |
| Routing | Tidak ada (langsung ke service) | Path-based & host-based routing |
| TLS Termination | Tidak built-in | Built-in + automatic renewal |
| L7 Features | Terbatas | Rate limiting, rewrites, gzip |
| Protokol | TCP/UDP (L4) | HTTP/HTTPS (L7) |
| Kompleksitas | Rendah | Menengah |
| Best For | Service non-HTTP (DB, gRPC L4) | Web applications, APIs |
# Service LoadBalancer (satu IP per service)
apiVersion: v1
kind: Service
metadata:
name: web-app-lb
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: web-app
# â Setiap service = satu LoadBalancer = lebih mahal
---
# Service ClusterIP + Ingress (satu IP untuk semua)
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
spec:
type: ClusterIP # Hanya cluster internal
ports:
- port: 80
targetPort: 8080
selector:
app: web-app
# â
Satu Ingress Controller + satu LoadBalancer untuk semua
Gunakan Service LoadBalancer untuk service non-HTTP yang membutuhkan TCP/UDP langsung (seperti database atau game server). Untuk semua HTTP/HTTPS traffic, gunakan Ingress untuk menghemat biaya dan mendapatkan fitur L7.
3. NGINX Ingress Controller
NGINX Ingress Controller adalah implementasi Ingress paling populer. Ada dua versi utama yang perlu Anda ketahui:
| Versi | Pengelola | Keunggulan |
|---|---|---|
| kubernetes/ingress-nginx | Kubernetes Community | Open-source, fleksibel, annotations-based config |
| nginxinc/kubernetes-ingress | NGINX Inc (F5) | Native NGINX Plus, enterprise support |
Instalasi dengan Helm
# Tambah repository helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update # Install NGINX Ingress Controller helm install nginx-ingress ingress-nginx/ingress-nginx \ --namespace ingress-system \ --create-namespace \ --set controller.replicaCount=2 \ --set controller.service.type=LoadBalancer \ --set controller.metrics.enabled=true # Cek status kubectl get pods -n ingress-system kubectl get svc -n ingress-system # Dapatkan External IP kubectl get svc -n ingress-system nginx-ingress-ingress-nginx-controller # NAME TYPE EXTERNAL-IP PORT(S) # nginx-ingress-ingress-nginx LoadBalancer 203.0.113.10 80:30080/TCP,443:30443/TCP # Test akses curl http://203.0.113.10
Instalasi dengan Manifest (tanpa Helm)
# Download dan terapkan manifest kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml # Verifikasi instalasi kubectl get pods -n ingress-nginx kubectl get svc -n ingress-nginx
Menggunakan Minikube
# Minikube sudah memiliki addon ingress minikube addons enable ingress # Verifikasi kubectl get pods -n ingress-nginx # Akses via minikube tunnel minikube tunnel
4. Path-Based Routing
Path-based routing memungkinkan Anda mengarahkan traffic ke service yang berbeda berdasarkan URL path. Misalnya, /api diarahkan ke API service, dan / ke frontend service.
Contoh Ingress dengan Path Routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
# Frontend - root path
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# API service
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 3000
# Auth service
- path: /auth
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 8080
# Static files
- path: /static
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80
# Specific file (exact match)
- path: /healthz
pathType: Exact
backend:
service:
name: health-service
port:
number: 80
PathType
| PathType | Penjelasan | Contoh |
|---|---|---|
Prefix | Match berdasarkan prefix URL (/api cocok /api/v1, /api/users) | /api cocok: /api, /api/v1, /api/users/123 |
Exact | Match exact path | /healthz hanya cocok: /healthz (bukan /healthz/live) |
ImplementationSpecific | Ditentukan oleh Ingress Controller | Tergantung konfigurasi controller |
Path Rewrite
# Rewrite target - hapus prefix sebelum forward ke backend
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
# /api/users â /users di backend service
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 3000
# Contoh routing:
# /api/users â backend: /users
# /api/users/123 â backend: /users/123
# /api â backend: /
5. Host-Based Routing
Host-based routing memungkinkan Anda mengarahkan traffic ke service berdasarkan hostname di URL. Ini sangat berguna untuk multi-tenant applications atau meng-host beberapa domain di satu cluster Kubernetes.
Contoh Multi-Host Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx
rules:
# Domain 1: App utama
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: main-app-service
port:
number: 80
# Domain 2: API
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 3000
# Domain 3: Blog / CMS
- host: blog.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress-service
port:
number: 80
# Domain 4: Admin panel
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8080
Gabungan Host + Path Routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: combined-ingress
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 3000
- path: /ws
pathType: Prefix
backend:
service:
name: websocket-svc
port:
number: 8080
- host: admin.example.com
http:
paths:
- path: /dashboard
pathType: Prefix
backend:
service:
name: dashboard-svc
port:
number: 80
- path: /settings
pathType: Prefix
backend:
service:
name: settings-svc
port:
number: 80
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â HOST + PATH ROUTING â â â â Internet â â â â â âŧ â â ââââââââââââââââââââââââââââââââââââââââââââ â â â NGINX INGRESS CONTROLLER â â â â â â â â Host: app.example.com â â â â âââ / â frontend-svc:80 â â â â âââ /api â api-svc:3000 â â â â âââ /ws â websocket-svc:8080 â â â â âââ /auth â auth-svc:8080 â â â â â â â â Host: admin.example.com â â â â âââ / â admin-svc:80 â â â â âââ /logs â logging-svc:80 â â â â â â â â Host: api.example.com â â â â âââ / â public-api-svc:3000 â â â ââââââââââââââââââââââââââââââââââââââââââââ â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
6. TLS Termination
TLS Termination memungkinkan Ingress Controller menangani HTTPS traffic â mendekripsi request di Ingress Controller, kemudian meneruskan request HTTP biasa ke service backend. Ini menghilangkan beban TLS dari aplikasi Anda.
TLS Manual dengan Secret
# Buat TLS Secret dari certificate dan key kubectl create secret tls app-tls-secret \ --cert=tls.crt \ --key=tls.key \ -n production # Verifikasi kubectl get secret app-tls-secret -n production
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
spec:
ingressClassName: nginx
tls:
# TLS untuk domain utama
- hosts:
- app.example.com
- www.example.com
secretName: app-tls-secret
# TLS untuk API (certificate terpisah)
- hosts:
- api.example.com
secretName: api-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 3000
Automatic TLS dengan cert-manager
cert-manager mengotomatiskan pembuatan dan perpanjangan TLS certificate menggunakan Let's Encrypt atau CA lainnya.
# Install cert-manager helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set installCRDs=true # Verifikasi kubectl get pods -n cert-manager
# ClusterIssuer untuk Let's Encrypt production
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
---
# ClusterIssuer untuk Let's Encrypt staging (testing)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
class: nginx
# Ingress dengan automatic TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auto-tls-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-auto-tls # cert-manager buat otomatis
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
# cert-manager akan:
# 1. Membuat Certificate resource otomatis
# 2. Request certificate dari Let's Encrypt
# 3. Validasi domain via HTTP-01 challenge
# 4. Simpan certificate di secret "app-auto-tls"
# 5. Auto-renew sebelum expiry
Let's Encrypt menggunakan rate limit. Saat testing, gunakan ClusterIssuer staging terlebih dahulu untuk menghindari terkena rate limit production. Baru beralih ke production setelah yakin konfigurasi benar.
7. Annotations NGINX Ingress
Annotations adalah cara utama untuk mengkonfigurasi behavior NGINX Ingress Controller. Setiap annotation dimulai dengan prefix nginx.ingress.kubernetes.io/.
Annotations Populer
| Annotation | Fungsi | Contoh |
|---|---|---|
rewrite-target | URL rewrite sebelum forward | /$2 |
ssl-redirect | Redirect HTTP ke HTTPS | "true" |
force-ssl-redirect | Paksa redirect ke HTTPS | "true" |
proxy-body-size | Max upload file size | "50m" |
proxy-read-timeout | Timeout untuk response | "120" |
proxy-send-timeout | Timeout untuk request | "120" |
rate-limit | Rate limiting | "100" |
enable-cors | Enable CORS headers | "true" |
cors-allow-origin | Allowed origins | "*" |
whitelist-source-range | IP whitelist | "10.0.0.0/8" |
basic-auth | Basic auth secret | "auth-secret" |
server-snippet | Custom NGINX server block | Custom NGINX directives |
configuration-snippet | Custom NGINX location block | Custom location directives |
Contoh Annotations Lengkap
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: production-ingress
annotations:
# TLS & Security
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts: "true"
nginx.ingress.kubernetes.io/hsts-max-age: "31536000"
nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
# Rate Limiting
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "50"
# Proxy Settings
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE"
nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
# IP Whitelist (opsional)
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,172.16.0.0/12"
# Custom NGINX snippet
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: DENY";
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-XSS-Protection: 1; mode=block";
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
Websocket Support
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
spec:
ingressClassName: nginx
rules:
- host: ws.example.com
http:
paths:
- path: /ws
pathType: Prefix
backend:
service:
name: websocket-service
port:
number: 8080
8. Advanced Configuration
Basic Authentication
# Buat file htpasswd htpasswd -c auth admin # Masukkan password saat prompt # Buat Kubernetes Secret kubectl create secret generic basic-auth \ --from-file=auth -n production
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: protected-ingress
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
ingressClassName: nginx
rules:
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80
Custom Error Pages
# ConfigMap untuk custom error pages
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-error-pages
data:
404: |
<html><body><h1>404 - Halaman Tidak Ditemukan</h1></body></html>
503: |
<html><body><h1>503 - Maintenance Mode</h1></body></html>
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: custom-errors-ingress
annotations:
nginx.ingress.kubernetes.io/custom-http-errors: "404,503"
nginx.ingress.kubernetes.io/default-backend: custom-error-pages
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
Global Configuration
# ConfigMap global untuk NGINX Ingress Controller apiVersion: v1 kind: ConfigMap metadata: name: nginx-ingress-controller namespace: ingress-system data: # Performance worker-processes: "4" max-worker-connections: "65536" keep-alive: "75" # Security ssl-protocols: "TLSv1.2 TLSv1.3" ssl-ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" hsts: "true" hsts-max-age: "31536000" # Proxy proxy-body-size: "20m" proxy-read-timeout: "60" proxy-send-timeout: "60" # Logging enable-access-log-for-default-backend: "true" log-format-upstream: '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"' # Features use-gzip: "true" gzip-level: "5" gzip-min-length: "256"
9. IngressClass
IngressClass memungkinkan Anda menjalankan beberapa Ingress Controller di satu cluster. Misalnya, satu controller untuk traffic publik dan satu lagi untuk traffic internal.
# IngressClass untuk public traffic
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: public-nginx
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
---
# IngressClass untuk internal traffic
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: internal-nginx
spec:
controller: k8s.io/ingress-nginx
---
# Ingress menggunakan IngressClass tertentu
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: public-app-ingress
spec:
ingressClassName: public-nginx # Gunakan class public
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: internal-app-ingress
spec:
ingressClassName: internal-nginx # Gunakan class internal
rules:
- host: internal-app.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: internal-service
port:
number: 80
10. Troubleshooting
Berikut panduan troubleshooting untuk masalah umum Ingress di Kubernetes:
# 1. Cek status Ingress
kubectl get ingress -A
kubectl describe ingress my-ingress -n production
# 2. Cek Ingress Controller logs
kubectl logs -n ingress-system -l app.kubernetes.io/name=ingress-nginx --tail=100
# 3. Cek apakah service ada dan healthy
kubectl get svc -n production
kubectl get endpoints -n production
# 4. Cek apakah pods berjalan
kubectl get pods -n production -l app=my-app
# 5. Test dari dalam cluster
kubectl run test-pod --rm -it --image=curlimages/curl -- \
curl http://app-service.production.svc.cluster.local
# 6. Cek external IP LoadBalancer
kubectl get svc -n ingress-system
# 7. Cek NGINX config yang di-generate
kubectl exec -n ingress-system -it \
$(kubectl get pods -n ingress-system -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}') \
-- cat /etc/nginx/nginx.conf | head -100
# 8. Cek TLS certificate
kubectl get secret app-tls-secret -n production -o yaml
openssl x509 -in tls.crt -text -noout
# 9. Cek events
kubectl get events -n production --sort-by='.lastTimestamp'
# 10. Cek DNS resolution
nslookup app.example.com
dig app.example.com
Masalah Umum
| Masalah | Penyebab | Solusi |
|---|---|---|
| 404 Not Found | Path/host tidak cocok | Cek rules di Ingress dan pathType |
| 502 Bad Gateway | Service/pod tidak ready | Cek endpoints dan pod logs |
| 503 Service Unavailable | Service tidak punya endpoints | Cek selector service cocok dengan pods |
| TLS cert error | Secret tidak ada atau expired | Cek secret, cert-manager logs |
| Pending External IP | LoadBalancer belum provisioned | Cek cloud provider, coba minikube tunnel |
| Rate limit hit | Rate limit annotation terlalu ketat | Tingkatkan limit atau whitelist IP |
11. Quiz Pemahaman
Uji pemahaman Anda tentang Kubernetes Ingress Controllers:
1. Apa fungsi utama Ingress Controller?
2. Apa fungsi cert-manager di Kubernetes?
3. Apa fungsi annotation nginx.ingress.kubernetes.io/rewrite-target?
4. Berapa IP publik yang dibutuhkan jika menggunakan Ingress untuk 10 service HTTP?
5. PathType apa yang cocok untuk path /api/v1/users/123 dengan rule /api?