Cara Deploy WordPress di Kubernetes Lengkap dengan SSL Let’s Encrypt
July 1, 2025
Tutorial

Tutorial ini menjelaskan langkah demi langkah, termasuk semua konfigurasi YAML, setup penyimpanan, database, hingga penerapan SSL otomatis menggunakan Cert Manager. Cocok untuk pemula maupun yang sudah terbiasa dengan Kubernetes. ✅
📂 Struktur Folder
.
├── cert-manager
│ ├── cert-manager-deploy.yaml
│ ├── cluster-issuer.yaml
│ └── namespace.yaml
├── ingress-nginx
│ ├── ingress-nginx-deploy.yaml
│ ├── ingress-nginx-svc.yaml
│ └── namespace.yaml
├── mysql
│ ├── deployment.yaml
│ ├── pvc.yaml
│ └── service.yaml
├── storage
│ ├── pv.yaml
│ └── storageclass.yaml
└── wordpress
├── deployment.yaml
├── ingress-www.yaml
├── pvc.yaml
├── redirect-to-www.yaml
└── service.yaml
🔥 Penjelasan Detail
📦 Storage
- storageclass.yaml → Membuat StorageClass bernama
local-storage
untuk PV lokal.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
- pv.yaml → Dua PersistentVolume, untuk
mysql
danwordpress
.
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-mysql
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: local-storage
hostPath:
path: /root/www.masdika.my.id/data/mysql
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-wordpress
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: local-storage
hostPath:
path: /root/www.masdika.my.id/data/wordpress
🗄️ MySQL
- pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 10Gi
- deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8
env:
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wpuser
- name: MYSQL_PASSWORD
value: wppassword
- name: MYSQL_ROOT_PASSWORD
value: rootpassword
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: mysql-pvc
- service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306
🌐 Ingress NGINX
- namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
- ingress-nginx-deploy.yaml → Deployment controller nginx
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
spec:
serviceAccountName: ingress-nginx
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.10.1
args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- ingress-nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
🔐 Cert Manager
- namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
- cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@masdika.my.id
privateKeySecretRef:
name: letsencrypt-prod-private-key
solvers:
- http01:
ingress:
class: nginx
- cert-manager-deploy.yaml
# Apply official manifest
# jalankan perintah:
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml
🖥️ WordPress
- pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 10Gi
- deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress:latest
env:
- name: WORDPRESS_DB_HOST
value: mysql
- name: WORDPRESS_DB_USER
value: wpuser
- name: WORDPRESS_DB_PASSWORD
value: wppassword
- name: WORDPRESS_DB_NAME
value: wordpress
ports:
- containerPort: 80
volumeMounts:
- name: wordpress-data
mountPath: /var/www/html
volumes:
- name: wordpress-data
persistentVolumeClaim:
claimName: wordpress-pvc
- service.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
selector:
app: wordpress
ports:
- protocol: TCP
port: 80
targetPort: 80
- ingress-www.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wordpress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.masdika.my.id
secretName: www-masdika-my-id-tls
rules:
- host: www.masdika.my.id
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80
- redirect-to-www.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-to-www
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/permanent-redirect: https://www.masdika.my.id$request_uri
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- masdika.my.id
secretName: masdika-my-id-tls
rules:
- host: masdika.my.id
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80
🛠️ Langkah Deploy
1️⃣ Deploy Storage
kubectl apply -f storage/
2️⃣ Deploy MySQL
kubectl apply -f mysql/
3️⃣ Deploy WordPress
kubectl apply -f wordpress/
4️⃣ Deploy Ingress NGINX
kubectl apply -f ingress-nginx/
5️⃣ Deploy Cert Manager
kubectl apply -f cert-manager/namespace.yaml
kubectl apply -f cert-manager/cluster-issuer.yaml
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml
(File cert-manager-deploy.yaml menjalankan perintah ke repo resmi cert-manager.)
6️⃣ Deploy Ingress untuk WordPress + Redirect
kubectl apply -f wordpress/redirect-to-www.yaml
kubectl apply -f wordpress/ingress-www.yaml
✅ Akses Domain
- https://www.masdika.my.id (Utama)
- https://masdika.my.id (Redirect ke www)

🧠 Troubleshooting
- 🚫 LoadBalancer Pending → Periksa konfigurasi MetalLB atau cloud provider.
- 🔐 SSL Error → Pastikan DNS sudah pointing, dan cek ClusterIssuer.
- ⚠️ PVC Error → Pastikan folder
/root/www.masdika.my.id/data/*
ada dan permission benar.