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
#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
#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
#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
#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
#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
#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
#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
#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
#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:
# 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
# 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.




