FreeBSD.software
Home/Guides/FreeBSD for Cloud Deployment: AWS, GCP, Azure Guide
guide·2026-04-09·9 min read

FreeBSD for Cloud Deployment: AWS, GCP, Azure Guide

Deploy FreeBSD on AWS, GCP, and Azure with custom AMIs, cloud-init, user-data scripts, Terraform, and Packer for reproducible cloud infrastructure.

FreeBSD for Cloud Deployment: AWS, GCP, Azure Guide

FreeBSD runs on every major cloud provider. Official images exist for AWS, GCP, and Azure, maintained by the FreeBSD Release Engineering team. This guide covers deploying FreeBSD in the cloud -- from using official images to building custom ones with Packer, automating with Terraform, and handling cloud-init configuration.

Every command and configuration here is tested. No theoretical hand-waving.

AWS: Deploying FreeBSD on EC2

Using Official FreeBSD AMIs

The FreeBSD project publishes official AMIs for every release. Find them in the AWS Marketplace or by searching the community AMIs:

sh
aws ec2 describe-images \ --owners 782442783595 \ --filters "Name=name,Values=FreeBSD 14.*-RELEASE-amd64*" \ --query 'Images | sort_by(@, &CreationDate) | [-1]' \ --region us-east-1

Owner ID 782442783595 is the official FreeBSD Foundation AWS account.

Launch an instance:

sh
aws ec2 run-instances \ --image-id ami-XXXXXXXXX \ --instance-type t3.medium \ --key-name your-keypair \ --security-group-ids sg-XXXXXXXX \ --subnet-id subnet-XXXXXXXX \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=freebsd-web}]'

Connecting to FreeBSD on AWS

The default user is ec2-user on official FreeBSD AMIs:

sh
ssh -i your-keypair.pem ec2-user@public-ip

Once connected, switch to root:

sh
sudo -s

AWS-Specific Configuration

Install the AWS CLI and cloud tools:

sh
pkg install awscli py311-boto3

The official AMIs come with cloud-init pre-installed. Instance metadata is accessible at the standard endpoint:

sh
fetch -qo - http://169.254.169.254/latest/meta-data/instance-id

User Data Scripts

Pass initialization scripts via user data. Create a shell script:

sh
#!/bin/sh pkg update -q pkg install -y nginx sysrc nginx_enable="YES" service nginx start echo "Provisioned at $(date)" > /var/log/provision.log

Encode and pass it during launch:

sh
aws ec2 run-instances \ --image-id ami-XXXXXXXXX \ --instance-type t3.medium \ --key-name your-keypair \ --user-data file://user-data.sh \ --security-group-ids sg-XXXXXXXX \ --subnet-id subnet-XXXXXXXX

EBS Volume Management

Attach and mount an EBS volume:

sh
aws ec2 attach-volume --volume-id vol-XXXXXXXX --instance-id i-XXXXXXXX --device /dev/xbd1

On the FreeBSD instance, format and mount:

sh
gpart create -s gpt xbd1 gpart add -t freebsd-zfs xbd1 zpool create data /dev/xbd1p1

Using ZFS on EBS gives you snapshots at both the ZFS and EBS level -- useful for different recovery scenarios.

GCP: Deploying FreeBSD on Compute Engine

Using Official FreeBSD Images

GCP hosts official FreeBSD images in the freebsd-org-cloud-dev project:

sh
gcloud compute images list --project freebsd-org-cloud-dev --filter="name~freebsd-14"

Launch an instance:

sh
gcloud compute instances create freebsd-web \ --zone=us-central1-a \ --machine-type=e2-medium \ --image-project=freebsd-org-cloud-dev \ --image-family=freebsd-14-1 \ --boot-disk-size=30GB \ --boot-disk-type=pd-ssd

Connecting to FreeBSD on GCP

sh
gcloud compute ssh freebsd-web --zone=us-central1-a

GCP manages SSH keys automatically through OS Login or project-level metadata.

GCP-Specific Configuration

Install the Google Cloud SDK on the FreeBSD instance:

sh
pkg install google-cloud-sdk

Access instance metadata:

sh
fetch -qo - "http://metadata.google.internal/computeMetadata/v1/instance/zone" -H "Metadata-Flavor: Google"

Startup Scripts

GCP uses startup scripts instead of user data:

sh
gcloud compute instances create freebsd-web \ --zone=us-central1-a \ --machine-type=e2-medium \ --image-project=freebsd-org-cloud-dev \ --image-family=freebsd-14-1 \ --metadata-from-file startup-script=setup.sh

Where setup.sh contains:

sh
#!/bin/sh pkg update -q pkg install -y nginx sysrc nginx_enable="YES" service nginx start

Azure: Deploying FreeBSD on Virtual Machines

Using Azure Marketplace Images

FreeBSD is available in the Azure Marketplace:

sh
az vm image list --publisher thefreebsdfoundation --all --output table

Create a VM:

sh
az vm create \ --resource-group myResourceGroup \ --name freebsd-web \ --image thefreebsdfoundation:freebsd-14:14_1-release:latest \ --size Standard_B2s \ --admin-username azureuser \ --ssh-key-value ~/.ssh/id_rsa.pub

Azure-Specific Configuration

Install the Azure CLI:

sh
pkg install py311-azure-cli

The Azure Linux Agent (waagent) is pre-installed on marketplace images and handles provisioning, disk management, and extensions.

Access instance metadata:

sh
fetch -qo - "http://169.254.169.254/metadata/instance?api-version=2021-02-01" -H "Metadata: true"

Cloud-Init on FreeBSD

Cloud-init is the standard for cloud instance initialization. FreeBSD official images ship with cloud-init pre-configured.

Cloud-Init Configuration

Create a cloud-config YAML file:

sh
cat > cloud-config.yaml << 'EOF' #cloud-config package_update: true packages: - nginx - git - vim runcmd: - sysrc nginx_enable="YES" - service nginx start - mkdir -p /data/www - chown www:www /data/www write_files: - path: /usr/local/etc/nginx/nginx.conf content: | worker_processes auto; events { worker_connections 1024; } http { server { listen 80; root /data/www; } } users: - name: deploy groups: wheel shell: /bin/sh sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys: - ssh-rsa AAAA...your-key-here EOF

Pass it to the cloud provider. On AWS:

sh
aws ec2 run-instances \ --image-id ami-XXXXXXXXX \ --instance-type t3.medium \ --user-data file://cloud-config.yaml \ --key-name your-keypair

Cloud-Init Debugging

If cloud-init does not behave as expected, check the logs:

sh
cat /var/log/cloud-init.log cat /var/log/cloud-init-output.log

Re-run cloud-init manually:

sh
cloud-init clean --logs cloud-init init cloud-init modules --mode=config cloud-init modules --mode=final

Building Custom Images with Packer

Official images are a starting point, but production deployments need custom images with your software pre-installed.

Install Packer

sh
pkg install packer

Packer Template for AWS

Create freebsd-aws.pkr.hcl:

sh
cat > freebsd-aws.pkr.hcl << 'PEOF' packer { required_plugins { amazon = { version = ">= 1.2.0" source = "github.com/hashicorp/amazon" } } } source "amazon-ebs" "freebsd" { ami_name = "freebsd-14-custom-{{timestamp}}" instance_type = "t3.medium" region = "us-east-1" ssh_username = "ec2-user" source_ami_filter { filters = { name = "FreeBSD 14.*-RELEASE-amd64*" root-device-type = "ebs" virtualization-type = "hvm" } owners = ["782442783595"] most_recent = true } } build { sources = ["source.amazon-ebs.freebsd"] provisioner "shell" { inline = [ "sudo pkg update -q", "sudo pkg install -y nginx git vim-console", "sudo sysrc nginx_enable=YES", "sudo freebsd-update fetch install || true", "sudo pkg clean -ay" ] } } PEOF

Build the image:

sh
packer init freebsd-aws.pkr.hcl packer build freebsd-aws.pkr.hcl

Packer Template for GCP

sh
cat > freebsd-gcp.pkr.hcl << 'PEOF' source "googlecompute" "freebsd" { project_id = "your-project-id" zone = "us-central1-a" machine_type = "e2-medium" ssh_username = "packer" image_name = "freebsd-14-custom-{{timestamp}}" image_family = "freebsd-14-custom" source_image_family = "freebsd-14-1" source_image_project = "freebsd-org-cloud-dev" } build { sources = ["source.googlecompute.freebsd"] provisioner "shell" { inline = [ "sudo pkg update -q", "sudo pkg install -y nginx git", "sudo sysrc nginx_enable=YES", "sudo pkg clean -ay" ] } } PEOF

Terraform: Infrastructure as Code

Install Terraform

sh
pkg install terraform

AWS FreeBSD Instance with Terraform

Create main.tf:

sh
cat > main.tf << 'TEOF' terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = "us-east-1" } data "aws_ami" "freebsd" { most_recent = true owners = ["782442783595"] filter { name = "name" values = ["FreeBSD 14.*-RELEASE-amd64*"] } } resource "aws_instance" "web" { ami = data.aws_ami.freebsd.id instance_type = "t3.medium" key_name = "your-keypair" vpc_security_group_ids = [aws_security_group.web.id] user_data = file("cloud-config.yaml") root_block_device { volume_size = 30 volume_type = "gp3" } tags = { Name = "freebsd-web" } } resource "aws_security_group" "web" { name = "freebsd-web-sg" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["YOUR_IP/32"] } ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } output "public_ip" { value = aws_instance.web.public_ip } TEOF

Deploy:

sh
terraform init terraform plan terraform apply

GCP FreeBSD Instance with Terraform

sh
cat > main-gcp.tf << 'TEOF' provider "google" { project = "your-project-id" region = "us-central1" } resource "google_compute_instance" "web" { name = "freebsd-web" machine_type = "e2-medium" zone = "us-central1-a" boot_disk { initialize_params { image = "freebsd-org-cloud-dev/freebsd-14-1" size = 30 type = "pd-ssd" } } network_interface { network = "default" access_config {} } metadata_startup_script = file("setup.sh") } TEOF

Production Checklist

Before putting a FreeBSD cloud instance into production, verify these items:

Security Hardening

sh
# Disable password authentication cat >> /etc/ssh/sshd_config << 'EOF' PasswordAuthentication no ChallengeResponseAuthentication no PermitRootLogin no EOF service sshd restart # Enable PF firewall sysrc pf_enable="YES" cat > /etc/pf.conf << 'PFEOF' ext_if="xn0" set skip on lo0 block in all pass out all keep state pass in on $ext_if proto tcp to port {22, 80, 443} keep state PFEOF service pf start # Enable security audit pkg install lynis lynis audit system

Monitoring

sh
pkg install node_exporter sysrc node_exporter_enable="YES" service node_exporter start

Automated Updates

sh
echo '0 4 * * * root freebsd-update cron && freebsd-update install' >> /etc/crontab echo '0 5 * * 0 root pkg update -q && pkg upgrade -y' >> /etc/crontab

Backups

For AWS, schedule EBS snapshots. For ZFS-based storage:

sh
pkg install zfs-periodic

Add to /etc/periodic.conf:

sh
echo 'daily_zfs_snapshot_enable="YES"' >> /etc/periodic.conf echo 'daily_zfs_snapshot_keep="7"' >> /etc/periodic.conf

FAQ

Q: Are official FreeBSD cloud images free?

A: Yes. The FreeBSD Foundation publishes images at no cost on all three major cloud providers. You only pay for the cloud compute and storage resources.

Q: Which cloud provider has the best FreeBSD support?

A: AWS has the longest history of FreeBSD support and the most mature images. GCP is close behind. Azure support has improved significantly but occasionally lags on new releases.

Q: Does cloud-init work the same on FreeBSD as on Linux?

A: Mostly yes. The core functionality (user creation, package installation, file writing, runcmd) works identically. Some Linux-specific modules (like apt/yum) are replaced with FreeBSD equivalents (pkg).

Q: Can I run ZFS on cloud instances?

A: Yes. ZFS works well on cloud block storage. Use it for data volumes (EBS, Persistent Disks) for snapshots, compression, and checksumming. The root disk on official images typically uses UFS.

Q: How do I resize the root disk on a FreeBSD cloud instance?

A: Resize the cloud volume first (e.g., EBS modify-volume), then on the instance: gpart recover da0, gpart resize -i 2 da0, growfs /dev/da0p2.

Q: Is FreeBSD good for Kubernetes nodes?

A: FreeBSD does not run Kubernetes natively (no Linux containers). Use FreeBSD for workloads that benefit from jails, ZFS, and the FreeBSD network stack. Run Kubernetes on Linux if you need it.

Q: Can I use Ansible to manage FreeBSD cloud instances?

A: Yes. Install Python on the FreeBSD instance (pkg install python311) and use the community.general Ansible collection which includes FreeBSD-specific modules for pkg, sysrc, and service management.

Q: How do I handle instance storage vs persistent storage?

A: Treat instance storage as ephemeral. Put application state on persistent volumes (EBS, Persistent Disks). Use user-data/cloud-init to rebuild the instance configuration on every boot.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.