用Terraform管理香港服务器基础设施:IaC自动化创建VPS + DNS + 防火墙规则完整实践
手动登录面板创建服务器、手动配置 DNS、手动设置防火墙——这套流程不仅耗时,还难以复现。当需要创建第二套环境(测试/灾备)时,靠记忆重现配置几乎必然出错。Terraform 的基础设施即代码(IaC)理念将服务器环境用代码描述,一条命令即可创建完整的香港服务器基础设施,且每次结果完全一致。
一、Terraform 工作原理
<code">
你编写 .tf 配置文件(声明期望的基础设施状态)
│
▼
terraform plan(对比当前状态与期望状态,生成变更计划)
│
▼
terraform apply(执行变更,调用云/IDC API)
│
├── 创建 VPS
├── 配置 DNS 记录(Cloudflare)
├── 设置防火墙规则
└── 输出服务器 IP / SSH 连接信息
terraform.tfstate(记录当前真实状态,是 Terraform 的「底账」)
二、安装 Terraform
<code"># Linux 安装 wget https://releases.hashicorp.com/terraform/1.9.5/terraform_1.9.5_linux_amd64.zip unzip terraform_1.9.5_linux_amd64.zip mv terraform /usr/local/bin/ terraform version # 本地开发机(macOS) brew tap hashicorp/tap brew install hashicorp/tap/terraform
三、项目目录结构
<code">/terraform-hk/ ├── main.tf # 主资源定义 ├── variables.tf # 变量声明 ├── outputs.tf # 输出值 ├── versions.tf # Provider 版本锁定 ├── terraform.tfvars # 变量赋值(含 API Key,不提交 Git) └── .gitignore # 排除 .tfvars 和 .tfstate
四、Provider 配置(Cloudflare + DigitalOcean 示例)
<code"># versions.tf
terraform {
required_version = ">= 1.9"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
# 远程状态存储(推荐:防止本地 tfstate 丢失)
backend "s3" {
bucket = "your-terraform-state-bucket"
key = "hk-infra/terraform.tfstate"
region = "us-east-1"
endpoint = "https://your-account.r2.cloudflarestorage.com"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
force_path_style = true
}
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
provider "digitalocean" {
token = var.do_token
}五、主资源定义(main.tf)
<code"># main.tf
# ── SSH 密钥(上传到 IDC)──
resource "digitalocean_ssh_key" "deploy_key" {
name = "hk-deploy-key"
public_key = file("~/.ssh/id_ed25519.pub")
}
# ── 香港 VPS(Droplet)──
resource "digitalocean_droplet" "hk_web" {
name = "hk-web-${var.environment}"
region = "sgp1" # 可替换为 IDC.Net 等支持 Terraform 的 Provider
size = var.droplet_size # "s-4vcpu-8gb" 对应 4核8G
image = "ubuntu-22-04-x64"
ssh_keys = [digitalocean_ssh_key.deploy_key.fingerprint]
# 首次启动脚本(user_data)
user_data = templatefile("${path.module}/cloud-init.yaml", {
hostname = "hk-web-${var.environment}"
admin_email = var.admin_email
})
tags = ["web", var.environment, "hongkong"]
# 创建完成后的本地执行(可选:自动运行 Ansible)
provisioner "local-exec" {
command = "sleep 30 && ansible-playbook -i '${self.ipv4_address},' site.yml"
}
}
# ── Cloudflare DNS 记录 ──
resource "cloudflare_record" "web_a" {
zone_id = var.cloudflare_zone_id
name = var.environment == "production" ? "@" : var.environment
value = digitalocean_droplet.hk_web.ipv4_address
type = "A"
ttl = 300
proxied = true # 通过 Cloudflare CDN
}
resource "cloudflare_record" "api_a" {
zone_id = var.cloudflare_zone_id
name = "api.${var.environment == "production" ? "" : "${var.environment}."}"
value = digitalocean_droplet.hk_web.ipv4_address
type = "A"
ttl = 300
proxied = true
}
# ── Cloudflare 防火墙规则(WAF)──
resource "cloudflare_ruleset" "rate_limiting" {
zone_id = var.cloudflare_zone_id
name = "Rate Limiting Rules"
kind = "zone"
phase = "http_ratelimit"
rules {
action = "block"
ratelimit {
characteristics = ["ip.src"]
period = 60 # 60 秒窗口
requests_per_period = 200 # 超过 200 请求则封锁
mitigation_timeout = 600 # 封锁 10 分钟
}
expression = "true"
description = "Global Rate Limit"
enabled = true
}
}六、变量文件
<code"># variables.tf
variable "environment" {
description = "部署环境(production / staging)"
type = string
default = "production"
}
variable "droplet_size" {
description = "VPS 配置规格"
type = string
default = "s-4vcpu-8gb"
}
variable "cloudflare_api_token" {
description = "Cloudflare API Token"
type = string
sensitive = true # 标记为敏感,不在计划输出中显示
}
variable "cloudflare_zone_id" {
description = "Cloudflare 域名 Zone ID"
type = string
}
variable "do_token" {
description = "DigitalOcean API Token"
type = string
sensitive = true
}
variable "admin_email" {
description = "管理员邮箱(用于 Let's Encrypt)"
type = string
}<code"># terraform.tfvars(不提交 Git,通过 .gitignore 排除) environment = "production" droplet_size = "s-4vcpu-8gb" cloudflare_api_token = "your_cf_api_token" cloudflare_zone_id = "your_zone_id" do_token = "your_do_token" admin_email = "admin@yourdomain.com"
七、输出值(outputs.tf)
<code"># outputs.tf
output "server_ip" {
description = "香港服务器公网 IP"
value = digitalocean_droplet.hk_web.ipv4_address
}
output "ssh_command" {
description = "SSH 连接命令"
value = "ssh root@${digitalocean_droplet.hk_web.ipv4_address}"
}
output "website_url" {
description = "网站访问地址"
value = "https://${cloudflare_record.web_a.hostname}"
}八、常用命令速查
<code"># 初始化(下载 Provider 插件) terraform init # 格式化代码 terraform fmt # 语法检查 terraform validate # 预览变更(不实际执行) terraform plan -out=tfplan # 执行变更 terraform apply tfplan # 销毁所有资源(谨慎!) terraform destroy # 查看当前状态 terraform show # 仅刷新状态(不变更资源) terraform refresh # 导入已有资源到 Terraform 管理 terraform import digitalocean_droplet.hk_web 123456789
九、多环境管理(Workspace)
<code"># 创建 staging 工作空间 terraform workspace new staging terraform workspace list # 当前工作空间会影响 var.environment 的默认值 # 切换到生产环境 terraform workspace select production terraform apply
十、总结
Terraform 将香港服务器的创建、DNS 配置、安全规则全部代码化,团队协作时每个人都能看到基础设施的完整定义,不再依赖个人记忆和文档。一套 Terraform 代码可以快速复制出完全一致的测试/灾备环境,是 DevOps 成熟度的重要标志。