In my earlier post, I shared an example of deploying UpCloud infrastructure using Terraform from scratch. In this post, I want to share how to deploy the infrastructure using available Terraform modules to speed up the set-up process, especially for common use cases like preparing a web server.
For instance, our need is to deploy a website with some conditions as follows.
- The website can be accessed through HTTPS. If the request is HTTP, it will be redirected to HTTPS.
-
There are 2 domains,
web1.yourdomain.com
andweb2.yourdomain.com
. But, users should be redirected to "web2" if they are visiting "web1".
There are 4 main modules that we need to set up the environment.
- Private network. It allows the load balancer to connect with the server and pass the traffic.
- Server. It is used to host the website.
- Load balancer. It includes backend and frontend configuration.
- Dynamic certificate. It is required to allow an HTTPS connection.
Before we configure the main modules. We should set some variables used in the configuration in the variables.tf
file. Then, we create a terraform.tfvars
file that contains the values for those variables.
# variables.tf
variable "upcloud_username" {
description = "UpCloud username"
type = string
}
variable "upcloud_password" {
description = "UpCloud password"
type = string
}
variable "zone" {
description = "UpCloud zone"
type = string
default = "sg-sin1"
}
variable "public_keys" {
description = "List of public keys for server access"
type = list(string)
}
# terraform.tfvars
upcloud_username = "xxx"
upcloud_password = "xxx"
zone = "sg-sin1"
public_keys = [
"ssh-ed25519 AAAAxxx",
"ssh-ed25519 AAAAxxx"
]
Firstly, we set up the private network as the code below.
# main.tf
provider "upcloud" {
username = var.upcloud_username
password = var.upcloud_password
}
module "private_network" {
source = "lukibsubekti/network-private/upcloud"
version = "1.0.2"
router_name = "my-router"
network_name = "my-network"
zone = var.zone
network = {
subnet = "10.0.10.0/24"
is_dhcp = true
family = "IPv4"
is_dhcp_default_route = false
gateway_address = "10.0.10.1"
}
}
Next, we set up the web server. In this example, we just run an Nginx server which will host a default HTML page on port 80. The login method uses public keys.
# main.tf
module "web_server" {
source = "lukibsubekti/web-server/upcloud"
version = "1.0.1"
zone = var.zone
hostname = "my-web-server"
plan = "DEV-1xCPU-2GB"
os = "ubuntu-22.04"
private_network = {
network_id = module.private_network.network_id
ip_address = "10.0.10.123"
}
login = {
send_password = "none"
keys = var.public_keys
}
user_data = <<-EOF
#!/bin/bash
sudo apt-get update
sudo apt-get install -y nginx
EOF
}
Now, we configure the load balancer. We define a single backend server and several frontend rules to direct or serve requests based on conditions we set.
# main.tf
locals {
web1 = "web1.yourdomain.com"
web2 = "web2.yourdomain.com"
}
module "loadbalancer" {
source = "lukibsubekti/loadbalancer-static/upcloud"
version = "1.0.2"
zone = var.zone
name = "my-loadbalancer"
private_network = {
name = "private-net"
id = module.private_network.network_id
}
backends = {
"my-website" = [
{
ip = module.web_server.networks.private.ip_address
port = 80
}
]
}
frontends = {
"my-http" = {
mode = "http"
port = 80
default_backend = "my-website"
}
"my-https" = {
mode = "http"
port = 443
default_backend = "my-website"
}
}
rules = {
# redirect HTTP traffic to HTTPS
"my-rule1" = {
frontend = "my-http"
priority = 100
matching_condition = "or"
matchers = {
request_header = [
{
method = "starts"
name = "Host"
value = local.web1
ignore_case = true
},
{
method = "starts"
name = "Host"
value = local.web2
ignore_case = true
}
]
}
actions = {
http_redirect = {
scheme = "https"
}
set_forwarded_headers = {
active = true
}
}
}
# redirect HTTPS traffic from web1 to web2
"my-rule2" = {
frontend = "my-https"
priority = 90
matchers = {
request_header = [
{
method = "starts"
name = "Host"
value = local.web1
ignore_case = true
}
]
}
actions = {
http_redirect = {
location = "https://${local.web2}"
}
set_forwarded_headers = {
active = true
}
}
}
# handle HTTPS traffic for web2
"my-rule3" = {
frontend = "my-https"
priority = 80
matchers = {
request_header = [
{
method = "starts"
name = "Host"
value = local.web2
ignore_case = true
}
]
}
actions = {
use_backend = {
backend_name = "my-website"
}
set_forwarded_headers = {
active = true
}
}
}
}
}
We also need to output some values including the server IP address and the load balancer DNS name. We set it in output.tf
file.
# output.tf
output "server_networks" {
value = module.web_server.networks
description = "Server networks"
}
output "loadbalancer_networks" {
value = module.loadbalancer.networks_map
description = "Load balancer networks"
}
Before we can configure the dynamic certificate, we should apply the current configuration to get the load balancer DNS name which will be added to our DNS record. It is necessary so that the certificate can be verified and generated by the certificate provider.
Initialize the module and apply the configuration.
terraform init
terraform apply
The server IP address |
The public DNS name of the load balancer |
Updated DNS record for our domain |
After the DNS record is updated. We can apply the dynamic certificate configuration.
# main.tf
module "certs" {
source = "lukibsubekti/certs-dynamic/upcloud"
version = "1.0.0"
name = "my-certs"
hostnames = [
local.web1,
local.web2
]
frontend_id = module.loadbalancer.frontends_map["my-https"].id
}
Reinitialize the module and apply the updated configuration.
terraform init
terraform apply
The certificate is verified |
Lastly, we can verify the result by visiting http://web1.yourdomain.com
that will be redirected to https://web2.yourdomain.com
.
Comments
Post a Comment