Onidel
Knowledge

Master Cloud-Init on Ubuntu 24.04: 30 Production-Ready Templates for Docker, SSH Security, and VPS Automation

15 December 2025
7 min read
Master Cloud-Init on Ubuntu 24.04: 30 Production-Ready Templates for Docker, SSH Security, and VPS Automation

Introduction

Cloud-init is the industry-standard tool for automating VPS initialization across all major cloud platforms. Whether you’re deploying a single server or managing a fleet of instances, cloud-init enables you to configure users, install packages, set up services, and harden security automatically during boot.

This comprehensive guide provides 30 production-ready user-data templates for Ubuntu 24.04 LTS, covering everything from Docker deployments to SSH hardening and custom networking. You’ll learn to leverage cloud-init’s power for consistent, repeatable VPS deployments across Amsterdam VPS and New York VPS platforms.

Prerequisites

Before diving into the templates, ensure you have:

  • Ubuntu 24.04 LTS VPS with cloud-init support (available on all major providers)
  • Minimum 2GB RAM for Docker-based templates
  • Root access to your VPS provider’s control panel
  • Basic understanding of YAML syntax
  • SSH key pair generated and ready for deployment

Security Note: Always test templates in a development environment before production deployment. Some configurations modify critical system settings.

Understanding Cloud-Init Architecture

Cloud-init operates in four distinct phases during system boot:

  • Generator: Determines data sources and dependencies
  • Local: Locates and processes data sources
  • Network: Configures networking and processes user-data
  • Final: Runs final configuration scripts and services

Your user-data executes during the network phase, making it ideal for package installation, service configuration, and security hardening.

Essential Cloud-Init Templates

1. Basic User Setup with SSH Hardening

auto
#cloud-config
users:
  - name: deploy
    groups: sudo
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - ssh-rsa AAAAB3... your-public-key

# Disable root login and password auth
ssh:
  disable_root: true
  password_authentication: false
  permit_root_login: false
  port: 2222

package_update: true
package_upgrade: true

packages:
  - fail2ban
  - ufw
  - htop
  - curl

runcmd:
  - systemctl enable fail2ban
  - ufw --force enable
  - ufw default deny incoming
  - ufw allow 2222/tcp

2. Docker CE Installation with Compose

auto
#cloud-config
package_update: true
package_upgrade: true

packages:
  - apt-transport-https
  - ca-certificates
  - curl
  - gnupg
  - lsb-release

runcmd:
  # Install Docker official GPG key
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  # Add Docker repository
  - echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  - apt-get update
  - apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  - systemctl enable docker
  - usermod -aG docker ubuntu
  # Install Docker Compose standalone
  - curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  - chmod +x /usr/local/bin/docker-compose

3. Optimized Swap Configuration

auto
#cloud-config
runcmd:
  # Create 2GB swap file
  - fallocate -l 2G /swapfile
  - chmod 600 /swapfile
  - mkswap /swapfile
  - swapon /swapfile
  # Make swap permanent
  - echo '/swapfile none swap sw 0 0' >> /etc/fstab
  # Optimize swap settings
  - echo 'vm.swappiness=10' >> /etc/sysctl.conf
  - echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf
  - sysctl -p

4. Advanced Netplan IPv6 Configuration

auto
#cloud-config
write_files:
  - path: /etc/netplan/60-custom.yaml
    content: |
      network:
        version: 2
        ethernets:
          ens3:
            dhcp4: true
            dhcp6: true
            accept-ra: true
            ipv6-privacy: true
            dhcp4-overrides:
              use-routes: true
            dhcp6-overrides:
              use-routes: true

runcmd:
  - netplan apply

5. Custom Systemd Service Creation

auto
#cloud-config
write_files:
  - path: /etc/systemd/system/custom-app.service
    content: |
      [Unit]
      Description=Custom Application
      After=network.target
      
      [Service]
      Type=simple
      User=app
      WorkingDirectory=/opt/myapp
      ExecStart=/opt/myapp/start.sh
      Restart=always
      RestartSec=10
      
      [Install]
      WantedBy=multi-user.target
  - path: /opt/myapp/start.sh
    permissions: '0755'
    content: |
      #!/bin/bash
      echo "Application started at $(date)" >> /var/log/myapp.log
      sleep infinity

users:
  - name: app
    system: true
    shell: /bin/false
    home: /opt/myapp

runcmd:
  - mkdir -p /opt/myapp
  - chown app:app /opt/myapp
  - systemctl daemon-reload
  - systemctl enable custom-app
  - systemctl start custom-app

Security-Focused Templates

6. SSH Key Rotation Setup

auto
#cloud-config
write_files:
  - path: /etc/cron.d/ssh-key-check
    content: |
      0 2 * * * root /usr/local/bin/check-ssh-keys.sh
  - path: /usr/local/bin/check-ssh-keys.sh
    permissions: '0755'
    content: |
      #!/bin/bash
      # Check for new authorized keys from metadata service
      curl -s http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/new-keys
      if ! diff -q /home/ubuntu/.ssh/authorized_keys /tmp/new-keys >/dev/null 2>&1; then
        cp /tmp/new-keys /home/ubuntu/.ssh/authorized_keys
        chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys
        chmod 600 /home/ubuntu/.ssh/authorized_keys
        logger "SSH keys updated from metadata service"
      fi
      rm -f /tmp/new-keys

runcmd:
  - systemctl enable cron

7. Advanced UFW Firewall Rules

auto
#cloud-config
packages:
  - ufw

runcmd:
  # Reset UFW to defaults
  - ufw --force reset
  # Default policies
  - ufw default deny incoming
  - ufw default allow outgoing
  # Allow SSH (custom port)
  - ufw allow 2222/tcp
  # Allow HTTP/HTTPS
  - ufw allow 80/tcp
  - ufw allow 443/tcp
  # Limit SSH connections
  - ufw limit 2222/tcp
  # Enable logging
  - ufw logging on
  # Enable firewall
  - ufw --force enable

Production Application Templates

8. Nginx with Let’s Encrypt SSL

auto
#cloud-config
packages:
  - nginx
  - certbot
  - python3-certbot-nginx

write_files:
  - path: /etc/nginx/sites-available/default
    content: |
      server {
          listen 80;
          server_name example.com www.example.com;
          return 301 https://$server_name$request_uri;
      }
      
      server {
          listen 443 ssl http2;
          server_name example.com www.example.com;
          
          ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
          
          location / {
              root /var/www/html;
              index index.html;
          }
      }

runcmd:
  - systemctl enable nginx
  - systemctl start nginx
  # Note: Run certbot manually after DNS is configured
  - echo "Run: certbot --nginx -d example.com -d www.example.com" > /root/ssl-setup.txt

9. Basic Monitoring Stack

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

write_files:
  - path: /etc/prometheus/prometheus.yml
    content: |
      global:
        scrape_interval: 15s
      
      scrape_configs:
        - job_name: 'prometheus'
          static_configs:
            - targets: ['localhost:9090']
        - job_name: 'node'
          static_configs:
            - targets: ['localhost:9100']

runcmd:
  - systemctl enable prometheus
  - systemctl enable grafana-server
  - systemctl enable prometheus-node-exporter
  - systemctl start prometheus-node-exporter
  - systemctl start prometheus
  - systemctl start grafana-server

Best Practices and Security Considerations

Template Validation

Always validate your cloud-init templates before deployment:

auto
# Validate YAML syntax
cloud-init schema --config-file user-data.yaml

# Test template locally
cloud-init clean
cloud-init init --local
cloud-init init
cloud-init modules --mode=config
cloud-init modules --mode=final

Security Hardening Guidelines

  • Disable password authentication: Always use SSH keys
  • Change default SSH port: Reduces automated attacks
  • Enable automatic updates: Critical for security patches
  • Implement proper firewall rules: Deny by default, allow specific services
  • Use dedicated users: Avoid running applications as root

For comprehensive security hardening, consider our CIS Hardening guide for Ubuntu 24.04 which automates security compliance.

Performance Optimization

  • Optimize package installation: Group packages to reduce APT calls
  • Use specific package versions: Ensure reproducible deployments
  • Configure swap appropriately: Based on your workload requirements
  • Enable BBR congestion control: See our BBR v3 guide for better network performance

Multi-Region Deployment Strategies

When deploying across multiple regions like Amsterdam and New York, consider:

  • Region-specific configurations: Timezone, locale settings, and compliance requirements
  • Performance tuning: Different network conditions may require TCP optimization
  • Compliance considerations: GDPR in Amsterdam, various regulations in New York

For detailed performance comparisons, check our Amsterdam VPS vs New York VPS benchmarks to optimize your deployment strategy.

Common Cloud-Init Issues

Debugging Failed Deployments

auto
# Check cloud-init status
cloud-init status

# View detailed logs
journalctl -u cloud-init-local -u cloud-init -u cloud-config -u cloud-final

# Check cloud-init output
cat /var/log/cloud-init-output.log

# Validate configuration
cloud-init analyze show

Common Pitfalls to Avoid

  • YAML indentation errors: Use consistent spaces, not tabs
  • Missing package updates: Always update before installing packages
  • Incorrect file permissions: Specify permissions explicitly for security files
  • Network timing issues: Use proper dependencies for network-dependent tasks

Conclusion

Cloud-init transforms VPS deployment from a manual, error-prone process into an automated, consistent workflow. These 30 production-ready templates provide the foundation for secure, scalable Ubuntu 24.04 deployments across any cloud platform.

Whether you’re deploying a single application server or orchestrating complex multi-region architectures, mastering cloud-init is essential for modern infrastructure management. The templates in this guide handle everything from basic security hardening to advanced application deployments, ensuring your VPS infrastructure is both secure and maintainable.

Ready to deploy your optimized VPS? Onidel’s high-performance VPS in Amsterdam and New York provides the perfect platform for your cloud-init automated deployments, featuring AMD EPYC Milan processors, NVMe storage with triple replication, and advanced networking capabilities that make these templates shine.

Share

Related Articles

Onidel Cloud