用Terraform管理香港服务器基础设施:IaC自动化创建VPS + DNS + 防火墙规则完整实践

用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 成熟度的重要标志。



Telegram