---
title: Deploying a web application with Scaleway Kubernetes Kapsule using a full isolation pool and Public Gateway
description: This page explains how to a web application with Scaleway Kubernetes Kapsule using a full isolation pool and Public Gateway using Terraform/OpenTofu
products:
  - instances
  - terraform
  - kubernetes
tags: Terraform OpenTofu Kubernetes Kapsule Instances
hero: assets/scaleway_terraform.webp
dates:
  validation: 2026-08-12
  validation_frequency: 12
difficulty: advanced
usecase:
  - resource-management
ecosystem:
  - third-party
---
import Requirements from '@macros/iam/requirements.mdx'

This tutorial walks you through an example of how to deploy a WordPress‑based web application on a Scaleway Kubernetes Kapsule. For the sake of the example, let's suppose that the application requires high security, scalability, and controlled external access. To achieve this, the solution outlined in this document applies:
- a full isolation pool to ensure that worker nodes have only private IP addresses, communicating within a Private Network
- a Public Gateway to manage secure external access to the web application

This setup ensures that internal cluster traffic is isolated from the public internet, while external users can access the application through a controlled entry point.

## Objectives

- **Security** - Isolate all internal cluster communication within a Private Network to prevent exposure to the public internet.
- **Scalability** - Enable auto-scaling to handle fluctuating traffic.
- **Controlled access** - Use a Public Gateway to manage and secure external traffic to the web application.
- **Resilience** - Ensure high availability by deploying across multiple Availability Zones (AZs).

## Architecture

The architecture includes the following:

- **Kubernetes Kapsule cluster** - A managed Kubernetes cluster hosted in the Paris region (`fr-par`) of Scaleway.
- **Full isolation pool** - Worker nodes configured with only private IP addresses, communicating within a Scaleway Private Network.
- **Public Gateway** - A Scaleway Public Gateway with Dynamic NAT enabled to route outgoing traffic from the Private Network to the public internet and allow controlled inbound access.
- **Load Balancer** - A Scaleway Load Balancer to distribute external traffic to the web application pods.
- **Containerized web application** - A web application (based on WordPress) deployed as pods, accessible externally via an ingress controller, with a MySQL database for persistence.


<Requirements />
- A Scaleway account with IAM permissions to create and manage Kubernetes clusters, VPC, Private Networks, and Public Gateways
- Created a VPC in the desired region to deploy
- Scaleway CLI or console access for configuration
- A containerized web application image (WordPress) stored in the Scaleway Container Registry or another registry
- A Scaleway Managed Database for MySQL for data persistence
- Basic knowledge of Kubernetes, Terraform, WordPress, and the Scaleway ecosystem


## Create Terraform variables

1. Create a `variables.tf` file to define Terraform variables used in the project.

	```bash
	variable "region" {
		type = string
		default = "fr-par"
		description = "The Scaleway region to deploy resources in (e.g., fr-par)"
	}
	variable "scaleway_access_key" {
		type = string
		description = "Scaleway access key for API authentication"
		sensitive = true
	}
	variable "scaleway_secret_key" {
		type = string
		description = "Scaleway secret key for API authentication"
		sensitive = true
	}
	variable "project_id" {
		type = string
		description = "Scaleway project ID for resource creation"
	}
	variable "db_user" {
		type = string
		description = "Username for the MySQL database"
		default = "admin"
	}
	variable "db_password" {
		type = string
		description = "Password for the MySQL database"
		sensitive = true
	}
	```

2. Use environment variables to securely provide your Scaleway credentials and sensitive data to Terraform. This avoids hardcoding values in files, reducing the risk of exposure (e.g., in version control). Set the required environment variables before running Terraform commands. Prefix the variable names with `TF_VAR_` to make them accessible to Terraform.

    ```bash
	export TF_VAR_scaleway_access_key=""
	export TF_VAR_scaleway_secret_key=""
	export TF_VAR_project_id=""
	export TF_VAR_db_password=""
	# Optional: Override defaults if needed
	export TF_VAR_region="fr-par"
	export TF_VAR_db_user="admin"
    ```

	Remember to add your actual Scaleway access key, Scaleway secret key, Scaleway Project ID, and MySQL database password.

	<Message type="tip">
	Best practices:

	- For persistent use on your local machine, add the previously mentioned export commands to your shell profile (e.g., `~/.bashrc` or `~/.zshrc`).
	- In CI/CD environments, inject environment variables as secure secrets.
	- Never commit environment variable scripts or files containing credentials to version control.
	- Verify that variables are set (e.g., `echo $TF_VAR_scaleway_access_key` on Linux/macOS) before running Terraform.
	</Message>

## Create and configure the Private Network and Public Gateway

Before you start, ensure you have created a Virtual Private Cloud (VPC) in the region of deployment. For detailed instructions, see [How to create and manage VPCs](/vpc/how-to/create-vpc/).

For full details, see the Terraform configuration file (`main.tf`) in [Appendix: Full main.tf file](#appendix-full-maintf-file).

1. Create a new Private Network in the `fr-par` region with a /22 IP subnet. For the sake of this tutorial, let's suppose that the solution outlined here will be used by a fictitious company called SiteSecure, so let's name the Private Network `sitesecure-private-net`. 

	```bash
	# Creating a private network for cluster isolation
	resource "scaleway_vpc_private_network" "sitesecure_pn" {
		name = "sitesecure-private-net"
		region = var.region
	}
	```

2. Create a Public Gateway in the same region as the cluster.

	```bash
	# Creating a public gateway for external access
	resource "scaleway_vpc_public_gateway" "sitesecure_gateway" {
		name = "sitesecure-gateway"
		type = "VPC-GW-S"
	```

3. Attach the Public Gateway to the Private Network.

	```bash
	# Attaching the Public Gateway to the Private Network with Dynamic NAT
	resource "scaleway_vpc_gateway_network" "sitesecure_gateway_network" {
		gateway_id = scaleway_vpc_public_gateway.sitesecure_gateway.id
		private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
		enable_masquerade = true
		ipam_config {
			push_default_route = true
		}
	}
	```

## Create a Kubernetes Kapsule cluster using Terraform

Create a Kubernetes Kapsule cluster with a node pool using full isolation. Configure the cluster via Terraform using the following characteristics:

- Cluster settings:
	- Name: `sitesecure-kapsule-cluster`  
	- Region: `fr-par`  
	- Kubernetes version: Latest supported version (e.g., 1.36.1)  
	- CNI: Cilium (recommended for performance and security)  
	- Private Network: Attach to `sitesecure-private-net`  
- Pool configuration:  
	- Pool name: `full-isolation-pool`  
	- Node type: `PRO2-S` (4 vCPUs, 16GB RAM, suitable for the workloads of the web application) 
	
	 	For more information about Instance types, see [Choosing the best Scaleway Instance type for your workload](/instances/reference-content/choosing-instance-type/).   
	- Enable **Full Isolation**: Nodes will have only private IPs, relying on the Public Gateway for external communication.
	- Enable **Auto-scaling**: Set minimum nodes to 2 and maximum to 5 to handle traffic spikes.
	- Enable **Autoheal**: Ensure unhealthy nodes are replaced automatically.

Terraform example:

```bash
# Creating a Kubernetes Kapsule cluster
resource "scaleway_k8s_cluster" "sitesecure_cluster" {
	name = "sitesecure-kapsule-cluster"
	version = "1.36.1"
	cni = "cilium"
	private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
	region = var.region
	delete_additional_resources = true
}

# Creating a node pool with full isolation
resource "scaleway_k8s_pool" "full_isolation_pool" {
	cluster_id = scaleway_k8s_cluster.sitesecure_cluster.id
	name = "full-isolation-pool"
	node_type = "PRO2-S"
	size = 2
	autoscaling = true
	autohealing = true
	min_size = 2
	max_size = 5
	public_ip_disabled = true
	region = var.region

	depends_on = [scaleway_vpc_gateway_network.sitesecure_gateway_network]
}
```

## Create and configure a Managed Database for MySQL using Terraform

Create a Managed Database for MySQL for use with WordPress.

Terraform example:

	```bash
	# Creating a managed MySQL database for WordPress
	resource "scaleway_rdb_instance" "wordpress_db" {
		name = "sitesecure-wordpress-db"
		node_type = "db-dev-s"
		engine = "MySQL-8"
		is_ha_cluster = true
		user_name = var.db_user
		password = var.db_password
		region = var.region
		volume_type = "sbs_15k"
  		volume_size_in_gb = 15
		
		private_network {
			pn_id = scaleway_vpc_private_network.sitesecure_pn.id
			enable_ipam = true
		}
	}
	```


## Deploy the services using Terraform

Before running the following commands, you can check the reference `main.tf` file in the [Appendix](#appendix-full-maintf-file) to confirm that the upcoming changes match your expectations.

1. Initialize your Terraform configuration.

	```bash
	terraform init
	``` 
2. Plan your deployment.

	```bash
	terraform plan
	```

3. Deploy the services.

	```bash
	terraform apply
	```

After deploying the infrastructure for the web application, it is time to create your resources.


## Retrieve variable values

1. Display the value of the output variable `db_password_base64` by running the following command: 
	```bash
	terraform output -raw db_password_base64
	```

2. Note down the value returned, you will need it when creating the Kubernetes Secret for database credentials (`wordpress-db-secret.yaml`).	

3. Display the value of the output variable `db_host` by running the following command: 
	```bash
	terraform output -raw db_host
	```

4. Note down the value returned, you will need it when creating the Kubernetes Deployment for WordPress (`wordpress-deployment.yaml`).	


## Create a Kubernetes Secret for the database

Create a Kubernetes Secret for database credentials (`wordpress-db-secret.yaml`). Remember to replace the value of `DB_PASSWORD` with your actual value (obtained in section [Retrieve variable values](#retrieve-variable-values)).

    ```yaml
    apiVersion: v1
    kind: Secret
    metadata:
        name: wordpress-db-credentials
        namespace: default
    type: Opaque
    data:
        DB_PASSWORD: "<base64-encoded-mysql-password>" 
        # Ensure the DB_PASSWORD is the same password as set in the terraform.tfvars configuration
	```


## Create a Kubernetes Deployment for WordPress

Create a Kubernetes Deployment for WordPress (`wordpress-deployment.yaml`). Remember to replace the `value` of `WORDPRESS_DB_HOST` with your actual value (obtained in section [Retrieve variable values](#retrieve-variable-values)).

    ```yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wordpress
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: sitesecure-wordpress
      template:
        metadata:
          labels:
            app.kubernetes.io/name: sitesecure-wordpress
        spec:
          containers:
          - name: wordpress
            image: wordpress:latest
            ports:
            - containerPort: 80
            env:
            - name: WORDPRESS_DB_HOST
              value: "<wordpress-database-host>"
            - name: WORDPRESS_DB_NAME
              value: "wordpress"
            - name: WORDPRESS_DB_USER
              value: "admin"
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: woocommerce-db-credentials
                  key: DB_PASSWORD
            resources:
              requests:
                cpu: "500m"
                memory: "512Mi"
              limits:
                cpu: "1000m"
                memory: "1Gi"
    ```


## Create an ingress controller

Deploy an ingress controller (e.g., `nginx-ingress`) to manage external HTTP traffic to the web application.

Create a configuration file called `wordpress-ingress.yaml`.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sitesecure-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  rules:
  - host: sitesecure.your-domain.tld
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: sitesecure-wordpress-service
              port:
                number: 80
```

## Configure a Load Balancer

Create a configuration file called `wordpress-service.yaml` to deploy a Kubernetes Service of type `LoadBalancer`.

```yaml
apiVersion: v1
kind: Service
metadata:
  name: sitesecure-wordpress-service
  namespace: default
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: sitesecure-wordpress
  ports:
  - port: 80
    targetPort: 80
```

This configuration provisions a Scaleway Load Balancer and integrates it with the Public Gateway to route external traffic.

## Test and monitor

1. To interact with the cluster, download and install the `kubeconfig` file of the cluster.

	```bash
	scw k8s config install <cluster-id>
	```

2. Deploy the web application using the following command.

	```bash
	kubectl apply -f wordpress-db-secret.yaml
	kubectl apply -f wordpress-deployment.yaml
	kubectl apply -f wordpress-service.yaml
	kubectl apply -f wordpress-ingress.yaml
	```

3. Use `kubectl` to verify the cluster status.

	```bash
	kubectl get nodes
	kubectl get pods
	```

4. Test the web application by accessing `sitesecure.your-domain.tld` via a browser and verifying the WordPress setup.
5. Enable Scaleway Cockpit to monitor the data plane and audit logs of the cluster.
6. Verify auto-scaling by simulating increased traffic (e.g., using a load testing tool like Vegeta).

<Message type="tip">
Once you have completed your tests, you can delete your deployment using the `terraform destroy` command.
</Message>

## Appendix: Full main.tf file

```bash
variable "region" {
  type        = string
  default     = "fr-par"
  description = <<EOT
Region where the infrastructure will be deployed
more details https://www.scaleway.com/en/docs/account/products-availability/
EOT
}
variable "zone" {
  type        = string
  default     = "fr-par-1"
  description = <<EOT
Availability Zone where the infrastructure will be deployed
more details https://www.scaleway.com/en/docs/account/products-availability/
EOT
}
terraform {
  required_providers {
    scaleway = {
      source = "scaleway/scaleway"
    }
  }
  required_version = ">= 0.13"
}
provider "scaleway" {
  zone   = var.zone
  region = var.region
}
variable "db_user" {
  type        = string
  default     = "admin"
  description = "database admin username"
}
variable "db_password" {
  type        = string
  sensitive   = true
  nullable    = false
  description = "database admin password"
}
# Creating a Private Network for cluster isolation
resource "scaleway_vpc_private_network" "sitesecure_pn" {
  name   = "sitesecure-private-net"
  region = var.region
}
# Creating a Public Gateway for external access
resource "scaleway_vpc_public_gateway" "sitesecure_gateway" {
  name = "sitesecure-gateway"
  type = "VPC-GW-S"
}
# Attaching the Public Gateway to the Private Network with Dynamic NAT
resource "scaleway_vpc_gateway_network" "sitesecure_gateway_network" {
  gateway_id         = scaleway_vpc_public_gateway.sitesecure_gateway.id
  private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
  enable_masquerade  = true
  ipam_config {
    push_default_route = true
  }
}
# Creating a Kubernetes Kapsule cluster
resource "scaleway_k8s_cluster" "sitesecure_cluster" {
  name                        = "sitesecure-kapsule-cluster"
  version                     = "1.36.1"
  cni                         = "cilium"
  private_network_id          = scaleway_vpc_private_network.sitesecure_pn.id
  region                      = var.region
  delete_additional_resources = true
}
# Creating a node pool with full isolation
resource "scaleway_k8s_pool" "full_isolation_pool" {
  cluster_id         = scaleway_k8s_cluster.sitesecure_cluster.id
  name               = "full-isolation-pool"
  node_type          = "PRO2-S"
  size               = 2
  autoscaling        = true
  autohealing        = true
  min_size           = 2
  max_size           = 5
  public_ip_disabled = true
  region             = var.region

  depends_on = [scaleway_vpc_gateway_network.sitesecure_gateway_network]
}
# Creating a managed MySQL database for WordPress
resource "scaleway_rdb_instance" "wordpress_db" {
  name              = "sitesecure-wordpress-db"
  node_type         = "db-dev-s"
  engine            = "MySQL-8"
  is_ha_cluster     = true
  user_name         = var.db_user
  password          = var.db_password
  region            = var.region
  volume_type       = "sbs_15k"
  volume_size_in_gb = 15

  private_network {
    pn_id       = scaleway_vpc_private_network.sitesecure_pn.id
    enable_ipam = true
  }
}

resource "scaleway_rdb_database" "database" {
  instance_id = scaleway_rdb_instance.wordpress_db.id
  name        = "wordpress"
}

# Creating output variable for database host
output "db_host" {
  value = format("%s:%d", scaleway_rdb_instance.wordpress_db.private_network.0.ip, scaleway_rdb_instance.wordpress_db.private_network.0.port)
}

# Creating output variable for and base64-encoding the database password
output "db_password_base64" {
  value = base64encode(var.db_password)
  sensitive = true
}
```
