Private Cloud Networking with VPC
NetActuate VPCs provide isolated private networks with a managed gateway for NAT, firewall, and bastion access. VMs deployed inside a VPC receive private IP addresses and access the internet through the gateway. This guide walks through creating a VPC, configuring firewall rules, setting up port forwarding, and deploying a VM.
What You Will Build
- A VPC with a private subnet and managed gateway
- Firewall rules allowing SSH and HTTP traffic
- A floating IP with reverse DNS
- DNAT port forwarding from the gateway to an internal VM
- A VM running inside the VPC with a private IP only
Prerequisites
- Terraform 1.0 or later
- A NetActuate API key (generate one at Account -> API Keys in the portal)
- The NetActuate Terraform provider configured:
terraform {
required_providers {
netactuate = {
source = "netactuate/netactuate"
version = ">= 2.0.0"
}
}
}
provider "netactuate" {
api_key = var.api_key
}
VPC Architecture
A NetActuate VPC consists of several components working together:
- Private network -- an isolated subnet (e.g.,
192.168.16.0/20) that is not routable on the public internet - Gateway -- a managed router with public IPv4 and IPv6 addresses that acts as the entry point to the VPC
- Default SNAT -- outbound internet access for all VMs through the gateway's public IP
- Firewall rules -- stateful packet filtering applied at the gateway
- VMs -- servers deployed inside the VPC that receive only private IP addresses via
vpc_reserved_network
Traffic flow: inbound traffic arrives at the gateway's public IP, passes through firewall rules, and is forwarded to internal VMs via DNAT. Outbound traffic from VMs is translated to the gateway's public IP via SNAT.
Step 1: Create the VPC
Define the VPC with a private network range, nameservers, and default SNAT enabled:
resource "netactuate_vpc" "main" {
label = "production-vpc"
location = "SJC"
network_ipv4 = "192.168.16.0/20"
nameservers = ["1.1.1.1", "8.8.8.8"]
enable_default_snat = true
}
Configuration breakdown:
label-- a human-readable name for the VPClocation-- the NetActuate data center codenetwork_ipv4-- the private subnet for the VPC; VMs receive addresses from this rangenameservers-- DNS servers pushed to VMs via DHCPenable_default_snat-- whentrue, all VMs can reach the internet through the gateway without additional configuration
Run the apply:
terraform apply
Terraform creates the VPC, provisions the gateway, and assigns public IPv4 and IPv6 addresses to it.
Step 2: Add Firewall Rules
The VPC gateway blocks all inbound traffic by default. Add firewall rules to allow the traffic you need:
resource "netactuate_vpc_gateway_firewall_rule" "ssh" {
vpc_id = netactuate_vpc.main.id
direction = "in"
protocol = "tcp"
port = "22"
source = "0.0.0.0/0"
action = "accept"
description = "Allow SSH from anywhere"
}
resource "netactuate_vpc_gateway_firewall_rule" "http" {
vpc_id = netactuate_vpc.main.id
direction = "in"
protocol = "tcp"
port = "80"
source = "0.0.0.0/0"
action = "accept"
description = "Allow HTTP from anywhere"
}
resource "netactuate_vpc_gateway_firewall_rule" "https" {
vpc_id = netactuate_vpc.main.id
direction = "in"
protocol = "tcp"
port = "443"
source = "0.0.0.0/0"
action = "accept"
description = "Allow HTTPS from anywhere"
}
Each rule specifies:
direction--infor inbound traffic,outfor outboundprotocol--tcp,udp, oricmpport-- the destination port number or rangesource-- the source CIDR; restrict this to your IP for SSH in productionaction--acceptordrop
Note: Firewall rules are stateful. An
acceptrule for inbound TCP port 22 automatically allows the return traffic.
Step 3: Allocate a Floating IP
Floating IPs are additional public addresses that you can assign to the VPC gateway. They are useful for services that need a dedicated IP or custom reverse DNS:
resource "netactuate_vpc_floating_ip" "web" {
vpc_id = netactuate_vpc.main.id
ptr = "web.example.com"
}
The floating IP is bound to the gateway. Use DNAT rules (next step) to forward traffic from the floating IP to specific internal VMs.
Step 4: Configure Port Forwarding
DNAT rules forward traffic arriving at the gateway's public IP (or a floating IP) to a specific internal VM:
resource "netactuate_vpc_gateway_dnat_rule" "web_http" {
vpc_id = netactuate_vpc.main.id
protocol = "tcp"
external_port = "80"
internal_ip = netactuate_server.web.vpc_reserved_network
internal_port = "80"
description = "Forward HTTP to web server"
}
resource "netactuate_vpc_gateway_dnat_rule" "web_https" {
vpc_id = netactuate_vpc.main.id
protocol = "tcp"
external_port = "443"
internal_ip = netactuate_server.web.vpc_reserved_network
internal_port = "443"
description = "Forward HTTPS to web server"
}
resource "netactuate_vpc_gateway_dnat_rule" "web_ssh" {
vpc_id = netactuate_vpc.main.id
protocol = "tcp"
external_port = "2222"
internal_ip = netactuate_server.web.vpc_reserved_network
internal_port = "22"
description = "Forward SSH on port 2222 to web server"
}
In the last rule, external port 2222 maps to internal port 22. This lets you SSH to the VM through the gateway on a non-standard port while the VM itself listens on the standard SSH port.
Step 5: Deploy a VM
Deploy a VM inside the VPC. The VM receives a private IP from the VPC subnet instead of a public IP:
resource "netactuate_server" "web" {
hostname = "web-01"
plan = "VR2x2x25"
location = "SJC"
image = "Ubuntu 24.04"
vpc_id = netactuate_vpc.main.id
ssh_key = var.ssh_public_key
}
output "web_private_ip" {
value = netactuate_server.web.vpc_reserved_network
description = "Private IP assigned to the web VM"
}
output "gateway_public_ip" {
value = netactuate_vpc.main.gateway_ipv4
description = "Public IPv4 address of the VPC gateway"
}
The vpc_reserved_network output contains the private IP address assigned to the VM from the VPC subnet. This is the address you use in DNAT rules and for internal communication between VMs.
Accessing VMs
VMs inside a VPC do not have public IP addresses. To connect via SSH, use the gateway as a bastion:
# Direct SSH through port forwarding (using the DNAT rule from Step 4)
ssh -p 2222 root@<gateway_public_ip>
Alternatively, use SSH proxying through the gateway:
# SSH proxy jump through the gateway
ssh -J root@<gateway_public_ip> root@<vm_private_ip>
For the proxy jump to work, the gateway must allow SSH access and the gateway must have connectivity to the VM's private IP (which it does by default).
Note: Replace
<gateway_public_ip>with the output ofterraform output gateway_public_ipand<vm_private_ip>with the output ofterraform output web_private_ip.
SNAT Rules
The default SNAT rule translates all outbound traffic from VMs to the gateway's primary public IP. If you need VMs to use a specific source IP for outbound traffic (for example, a floating IP), create a custom SNAT rule:
resource "netactuate_vpc_gateway_snat_rule" "web_outbound" {
vpc_id = netactuate_vpc.main.id
source = netactuate_server.web.vpc_reserved_network
snat_ip = netactuate_vpc_floating_ip.web.address
description = "Web server outbound via floating IP"
}
This ensures that outbound traffic from the web VM appears to originate from the floating IP instead of the gateway's default address.
Outputs Reference
| Output | Description |
|---|---|
netactuate_vpc.main.id | VPC identifier for use in other resources |
netactuate_vpc.main.gateway_ipv4 | Gateway public IPv4 address |
netactuate_vpc.main.gateway_ipv6 | Gateway public IPv6 address |
netactuate_server.web.vpc_reserved_network | Private IP assigned to the VM |
netactuate_vpc_floating_ip.web.address | Floating IP address |
Teardown
To remove all VPC resources:
terraform destroy
This deletes the VMs, firewall rules, DNAT/SNAT rules, floating IPs, and the VPC itself. Terraform handles the dependency ordering automatically.
Reference
- Repository: netactuate-terraform-vpc -- complete working examples
- Provider docs: VPC Terraform Reference
Related Guides
Need Help?
Contact support@netactuate.com or open a support ticket from the portal.