Reusable, generic cloud-init configuration templates for common server infrastructure patterns. These templates are designed to be included in your own cloud-init configurations via #include directives.
These templates follow a composable pattern:
- Generic base templates (this repo) - safe to open source
- Your server configurations (private repo) - domain-specific customizations
# your-private-repo/servers/web-server.yaml
#cloud-config-archive
# Environment setup (runs first)
- type: text/cloud-config
content: |
write_files:
- path: /etc/environment.d/90-infrastructure.conf
content: |
ADMIN_EMAIL="[email protected]"
AWS_REGION="us-west-2"
permissions: '0644'
owner: root:root
# Include base templates
- type: text/x-include-url
content: |
#include
https://raw.githubusercontent.com/your-org/cloud-init-templates/main/base/hardening.yaml
https://raw.githubusercontent.com/your-org/cloud-init-templates/main/base/docker.yaml
# Your application-specific configuration
- type: text/cloud-config
content: |
# Your app config here...Some templates come in multiple variants to support different use cases:
- Node.js: Choose between
nodejs-22.yaml(LTS) ornodejs-24.yaml(Latest) based on your application requirements - PostgreSQL: Single template
postgres.yamlinstalls latest version from PostgreSQL's official repository
- Purpose: Security hardening for Ubuntu servers
- Features: UFW firewall, fail2ban, automatic security updates, SSH hardening
- Environment Variables: None required
- Use Case: Apply to all production servers
⚠️ CAUTION: This configuration reboots the server at 2AM UTC time if there are updates that required a reboot. You may not want this.
- Purpose: Docker CE installation and configuration
- Features: Latest Docker CE, docker-compose, systemd integration
- Environment Variables: None required
- Use Case: Container-based applications
⚠️ CAUTION: You should look into more secure docker-like replacements, like podman.
- Purpose: Critical system alerts via AWS SES
- Features: Login notifications, disk/system monitoring, service failure alerts
- Environment Variables:
DEVOPS_EMAIL,ALERTS_EMAIL,AWS_REGION - Use Case: Production monitoring and incident response
- Purpose: Node.js runtime installation
- Features: Node.js 22.x or 24.x LTS via NodeSource repository
- Environment Variables: None required
- Use Case: Node.js applications
- Purpose: PostgreSQL database installation
- Features: Latest PostgreSQL from official PostgreSQL repository
- Environment Variables: None required
- Use Case: Database servers
Templates use environment variables loaded from /etc/environment.d/90-infrastructure.conf for customization without hardcoded values.
You cannot mix #include with #cloud-config in the same user-data. Instead, use #cloud-config-archive to combine multiple formats.
Correct approach with cloud-config-archive:
#cloud-config-archive
# 1. Create environment files first
- type: text/cloud-config
content: |
write_files:
- path: /etc/environment.d/90-infrastructure.conf
content: |
DEVOPS_EMAIL="[email protected]"
permissions: '0644'
owner: root:root
# 2. Include base templates
- type: text/x-include-url
content: |
#include
https://raw.githubusercontent.com/your-org/cloud-init-templates/main/base/email-alerts.yaml
# 3. Additional configuration
- type: text/cloud-config
content: |
merge_how:
- name: list
settings: [append]
- name: dict
settings: [no_replace, recurse_list]
packages: [...]Why this approach works: Cloud-config-archive processes each section in order, ensuring environment files are created before included templates run.
Create the environment file in your server configuration:
# In your private server configs (using cloud-config-archive)
#cloud-config-archive
- type: text/cloud-config
content: |
write_files:
- path: /etc/environment.d/90-infrastructure.conf
content: |
# Email Configuration
DEVOPS_EMAIL="[email protected]"
ALERTS_EMAIL="[email protected]"
ADMIN_EMAIL="[email protected]"
# Infrastructure
AWS_REGION="us-west-2"
BACKUP_RETENTION_DAYS="14"
permissions: "0644"
owner: root:rootTemplates use environment variables for customization. Common variables include DEVOPS_EMAIL, ALERTS_EMAIL, AWS_REGION, and SSH_PORT.
📋 Complete reference: See ENVIRONMENT_VARIABLES.md for all available variables, their purposes, and defaults.
# Create your own copy
gh repo fork your-org/cloud-init-templates# servers/web-server.yaml
#cloud-config-archive
# Environment setup (runs first)
- type: text/cloud-config
content: |
write_files:
- path: /etc/environment.d/90-infrastructure.conf
content: |
DEVOPS_EMAIL="[email protected]"
ALERTS_EMAIL="[email protected]"
AWS_REGION="us-west-2"
permissions: '0644'
owner: root:root
# Include base templates
- type: text/x-include-url
content: |
#include
https://raw.githubusercontent.com/your-org/cloud-init-templates/main/base/hardening.yaml
https://raw.githubusercontent.com/your-org/cloud-init-templates/main/base/docker.yaml
# Your application-specific config
- type: text/cloud-config
content: |
packages:
- nginx
runcmd:
- systemctl enable nginx
- systemctl start nginxMost cloud providers accept cloud-init data during instance creation. Point to your server configuration:
# Use raw GitHub URL for your server config
https://raw.githubusercontent.com/your-org/your-servers/main/servers/web-server.yaml- ✅ No hardcoded secrets - All sensitive values use environment variables
- ✅ Generic configurations - Domain-agnostic settings only
- ✅ Sensible defaults - Safe fallback values provided
- ✅ Open source friendly - Safe to publish publicly
- 🔐 Keep private - Contains your domain-specific secrets
- 🔐 Environment variables - Store sensitive values in env files
- 🔐 Least privilege - Only expose what's necessary for deployment
cloud-init-templates/
├── README.md # This file
├── ENVIRONMENT_VARIABLES.md # Environment variable reference
├── base/ # Base templates
│ ├── docker.yaml # Docker installation
│ ├── email-alerts.yaml # AWS SES alerting
│ ├── hardening.yaml # Security hardening
│ ├── nodejs-22.yaml # Node.js 22.x runtime
│ ├── nodejs-24.yaml # Node.js 24.x runtime
│ └── postgres.yaml # PostgreSQL from official repo
├── examples/ # Example server configs
│ ├── search-server.yaml # Search server with Meilisearch
│ └── web-server.yaml # Web application server
└── tests/ # Validation test suite
├── README.md # Testing documentation
├── run-all-tests.sh # Comprehensive test runner
├── test-email-alerts.sh # Email alerting tests
├── test-hardening.sh # Security hardening tests
├── test-security.sh # General security tests
└── utils.sh # Shared testing utilities
- Fork the repository
- Create a feature branch:
git checkout -b feature/new-template - Follow the template standards:
- Use environment variables for customization
- Provide sensible defaults
- Include comprehensive comments
- Test with multiple distributions
- Submit a pull request
- Environment Loading: All scripts must load env vars:
[ -f /etc/environment.d/90-infrastructure.conf ] && . /etc/environment.d/90-infrastructure.conf
- Sensible Defaults: Always provide fallback values:
EMAIL="${ADMIN_EMAIL:-admin@example.com}" - Documentation: Clearly document required environment variables
- Security: No hardcoded secrets or domain-specific information
See the examples/ directory for complete server configuration examples showing how to combine multiple base templates.
- Documentation: Cloud-Init Docs
MIT License - see LICENSE file for details.
🔧 Infrastructure as Code • 🔒 Security First • 🚀 Production Ready