Search code examples
ruby-on-railsgoogle-cloud-platformterraformdnskamal

Google domains .dev domain not working with Compute VM Instance


I registered a domain with google domains. mycompany.dev. I have a development server going on a VM instance that has a ruby on rails 8 app deployed to it and it works splendidly when it's accessed over http using the ip address.

I took the next step of turning on Kamal's ssl terminating proxy layer for myapp-development.mycompany.dev

I have cloud dns set up for the domain, and in cloud DNS I have a DNS Zone set up for 1myapp-development.mycompany.dev` with an A name record pointing at my VM instance's IP. Everything except the domain regitration itself was done with terraform.

I can not get a request to get through to this server through the domain name for the life of me. I don't know what it might be (except I suppose that it's a subdomain, but I don't really need the TLD to do anything). Chrome gives DNS_PROBE_FINISHED_NXDOMAIN

Terraform code provided below. I'm not sure what could be wrong.

provider "google" {
  project = "my-project"
  region  = "us-central1"
  zone    = "us-central1-c"
}

#########################################
# Networking
#########################################
# VPC
resource "google_compute_network" "vpc" {
    name                    = "myapp-development-vpc"
    auto_create_subnetworks = false
}

# Subnet
resource "google_compute_subnetwork" "subnet" {
  name          = "myapp-development-subnet"
  region        = "us-central1"
  network       = google_compute_network.vpc.id
  ip_cidr_range = "10.0.10.0/24"
}

resource "google_compute_firewall" "default" {
  name    = "myapp-development-firewall"
  network = google_compute_network.vpc.name
  direction = "INGRESS"
  description = "Firewall which allows only HTTP, HTTPS and SSH traffic"
  
  # TODO: Take out port 80 for production
  allow {
    protocol = "tcp"
    ports    = [80, 443, 22]
  }

  # TODO: Switch to IAP for SSH access
  source_ranges = ["0.0.0.0/0"]
}

resource "google_compute_address" "static_ip" {
  name         = "myapp-development-static-ip"
  region       = "us-central1"  # Specify the region
  address_type = "EXTERNAL"     # For an external static IP. You can use INTERNAL if needed.
}

#########################################
# DNS
#########################################

resource "google_dns_managed_zone" "dns_zone" {
    name        = "${var.subdomain_name}-dns-zone"
    dns_name    = "${var.subdomain_name}.mycompany.dev."
    description = "DNS managed zone for ${var.subdomain_name}"
}

resource "google_dns_record_set" "a" {
    name            = google_dns_managed_zone.dns_zone.dns_name
    managed_zone    = google_dns_managed_zone.dns_zone.name
    type            = "A"
    ttl             = 300
    rrdatas         = [google_compute_instance.myapp_development_n1.network_interface.0.access_config.0.nat_ip]
}


#########################################
# Docker Repository
#########################################
resource "google_artifact_registry_repository" "myapp_development" {
  location      = "us-central1"
  repository_id = "myapp-development"
  description   = "Mycompany myapp docker repository"
  format        = "DOCKER"

  docker_config {
    immutable_tags = false
  }
}

resource "google_service_account" "artifact_registry_sa" {
  account_id   = "myapp-artifact-registry-sa"
  display_name = "Custom SA for Artifact Registry"
}

# Grant Artifact Registry Reader permission to the service account
resource "google_project_iam_binding" "artifact_registry_reader" {
  project = "my-project"
  role    = "roles/artifactregistry.reader"
  members = [
    "serviceAccount:${google_service_account.artifact_registry_sa.email}"
  ]
}

# Grant Artifact Registry Writer permission to the service account
resource "google_project_iam_binding" "artifact_registry_writer" {
  project = "my-project"
  role    = "roles/artifactregistry.writer"
  members = [
    "serviceAccount:${google_service_account.artifact_registry_sa.email}"
  ]
}

#########################################
# Compute VM Instances
#########################################

resource "google_compute_instance" "myapp_development_n1" {
  description  = "App Node 1"
  name         = "myapp-n1"
  machine_type = "e2-medium"
  zone         = "us-central1-a"
  allow_stopping_for_update = true

  tags = ["web", "worker"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    subnetwork = google_compute_subnetwork.subnet.name 
    access_config {
      nat_ip = google_compute_address.static_ip.address
    }
  }

  metadata = {
    ssh-keys = "${var.ssh_host_user}:${var.ssh_key}"
  }


  metadata_startup_script = "echo hi > /test.txt"

  service_account {
    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
    email  = google_service_account.myapp_account.email
    scopes = ["cloud-platform"]
  }
}

resource "google_service_account" "myapp_account" {
  account_id   = "myapp-service-account"
  display_name = "Custom SA for VM Instance"
}

#########################################
# Secrets
#########################################

resource "google_secret_manager_secret" "pg_password" {
  secret_id = "myapp-development-pg-password"

  replication {
    auto {}
  }
}

resource "google_secret_manager_secret" "artifact_repository_key" {
  secret_id = "myapp-development-artifact-repository-key"

  replication {
    auto {}
  }
}

resource "google_secret_manager_secret" "rails_master_key" {
  secret_id = "myapp-development-rails-master-key"

  replication {
    auto {}
  }
}

Solution

  • In this case, creating the domain automatically created a dns managed zone for mycompany.dev. As a result the managed zone for myapp.mnycompany.dev never resovled, because it was looking at the higher precedence once.

    I changed the terraform code to not create a managed zone and just add the subdomain a record to the main managed zone for the domain

    resource "google_dns_record_set" "a" {
        name            = "${var.subdomain_name}.mycompany.dev."
        managed_zone    = "mycompany-dev"
        type            = "A"
        ttl             = 300
        rrdatas         = [google_compute_instance.myapp_development_n1.network_interface.0.access_config.0.nat_ip]
    }
    
    

    This started working immediately. I suspect also deleting the parent managed zone would also work.