VPS Server Provisioning with Cloud-Init: Automate Initial Setup and Configuration

Cloud-Init is the industry-standard tool for automating the initial bootstrapping of cloud and VPS instances. When you spin up a new server, Cloud-Init reads a user-data configuration file and executes setup tasks — creating users, installing packages, writing config files — before the system even becomes reachable via SSH. This guide walks through practical Cloud-Init configurations for production VPS deployments.

What Is Cloud-Init and Why Use It?

Cloud-Init runs on the first boot of a VPS instance. It supports multiple input formats (YAML, shell scripts, cloud-config) and works with every major VPS provider. Instead of manually running apt update && apt upgrade after provisioning, you define everything once in a Cloud-Init template and reuse it across deployments.

Benefits include: reproducible server setups, reduced human error, faster provisioning, and a documented infrastructure-as-code approach. If you manage multiple VPS instances, Cloud-Init is the foundation for consistency. For providers that support custom images, see which VPS plans include Cloud-Init support on our comparison table.

Essential Cloud-Init Configurations

1. Basic Security Hardening

This cloud-config disables password authentication, creates a sudo user with your SSH key, and configures the firewall:

#cloud-config
users:
  - name: deploy
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - "ssh-ed25519 AAAAC3... your-public-key"

ssh_pwauth: false
disable_root: true

packages:
  - ufw
  - fail2ban
  - unattended-upgrades

runcmd:
  - ufw allow 22/tcp
  - ufw allow 80/tcp
  - ufw allow 443/tcp
  - ufw --force enable
  - systemctl enable --now fail2ban

2. Web Server Bootstrap (Nginx + PHP + Let’s Encrypt)

#cloud-config
package_update: true
package_upgrade: true

packages:
  - nginx
  - php-fpm
  - php-mysql
  - certbot
  - python3-certbot-nginx
  - mariadb-server
  - redis-server

write_files:
  - path: /etc/nginx/sites-available/default
    content: |
      server {
          listen 80 default_server;
          server_name _;
          root /var/www/html;
          index index.php index.html;
          location / { try_files $uri $uri/ =404; }
          location ~ \.php$ {
              include snippets/fastcgi-php.conf;
              fastcgi_pass unix:/run/php/php8.3-fpm.sock;
          }
      }

runcmd:
  - rm -f /etc/nginx/sites-enabled/default
  - ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
  - systemctl enable --now nginx php8.3-fpm mariadb redis-server

3. Monitoring Stack Deployment (Prometheus + Node Exporter)

#cloud-config
packages:
  - prometheus-node-exporter

runcmd:
  - useradd --no-create-home --shell /bin/false prometheus
  - cd /opt
  - wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
  - tar xvf prometheus-*.tar.gz
  - mv prometheus-*/ prometheus/
  - chown -R prometheus:prometheus /opt/prometheus
  - cat > /etc/systemd/system/prometheus.service << EOF
[Unit]
Description=Prometheus
After=network.target

[Service]
User=prometheus
ExecStart=/opt/prometheus/prometheus --config.file=/opt/prometheus/prometheus.yml
Restart=always

[Install]
WantedBy=multi-user.target
EOF
  - systemctl enable --now prometheus

Testing Your Cloud-Init Configuration

Before deploying to production, validate your cloud-config locally:

# Install cloud-init locally
sudo apt install cloud-init
cloud-init devel schema --config-file your-config.yaml

Most VPS providers let you paste the cloud-config YAML directly in their control panel or API. For providers that don't support Cloud-Init natively, you can append it as a post-install script via their provisioning API. Compare VPS providers with Cloud-Init support to choose the right platform.

Best Practices

  • Always set ssh_pwauth: false and disable_root: true for security.
  • Keep Cloud-Init configurations in version control alongside your application code.
  • Use write_files for static configs and runcmd only for dynamic setup steps.
  • Test configurations on a disposable VPS before applying to production servers.

Mastering Cloud-Init saves hours of repetitive SSH sessions and ensures every VPS you deploy follows the exact same hardened baseline. For upcoming server projects, check the latest VPS deals and provisioning options.

Leave a Reply