Automated infrastructure provisioning and deployment for Ubuntu servers using Ansible. This playbook configures system packages, deploys Nginx with HTTPS/SSL, and deploys website applications.
Target Environment: Azure Linux VMs (Ubuntu)
Server: 135.225.128.201
Primary Protocol: HTTPS (TLS 1.3)
- Quick Start
- Project Structure
- Prerequisites
- Configuration
- Deployment
- Roles Overview
- Nginx Configuration
- Security
- Troubleshooting
# 1. Install Ansible
sudo apt install ansible
# 2. Edit inventory and credentials
nano inventory.ini
ansible-vault edit group_vars/myserver/vault.yml
# 3. Run the playbook
ansible-playbook -i inventory.ini setup.yml --ask-vault-passAnsible_Configuration_Management/
├── inventory.ini # Server inventory & variables
├── setup.yml # Main playbook (entry point)
├── Readme.md # This documentation
├── group_vars/
│ └── myserver/
│ └── vault.yml # Encrypted secrets (Ansible Vault)
└── roles/
├── base/ # System initialization
│ └── tasks/main.yml # Updates, security tools, fail2ban
├── nginx/ # Web server setup
│ ├── tasks/main.yml # Installation, SSL certificate generation
│ └── files/nginx.conf # Nginx configuration with HTTPS and restarting
├── app/ # Website deployment
│ ├── tasks/main.yml # Copy & extract website files
│ └── files/website.zip # Website tarball (Feane template)
└── ssh/ # SSH key-based authentication
└── tasks/main.yml # SSH key setup
- Ansible 2.9+ (
pip install ansibleorapt install ansible) - Python 3.6+
- SSH client (for connecting to target)
- ansible-vault (included with Ansible)
- Ubuntu 20.04 LTS or later
- SSH access with username/password or keys
- Sudo privileges (for package installation & service management)
- Port 22 (SSH) open for connections
- Ports 80 & 443 (HTTP/HTTPS) open in firewall
- Security Group must allow:
- Inbound: Port 443 (HTTPS)
- Inbound: Port 22 (SSH) - from your IP
- Outbound: All (for package downloads)
[myserver]
135.225.128.201 # Your server's public IP
[myserver:vars]
ansible_user=myserver # SSH username
ansible_ssh_port=22 # SSH port (default: 22)Create encrypted vault file with credentials:
ansible-vault create group_vars/myserver/vault.ymlAdd required variables:
# SSH password for initial setup
ssh_password: "your_secure_password_here"
# Sudo password (if different from SSH password)
ansible_become_password: "your_sudo_password_here"Current configuration:
- Protocol: HTTPS only (TLS 1.3)
- Port: 443
- Root Directory:
/var/www/html/feane-1.0.0 - Default Page:
index.html - SSL Certificate:
/etc/nginx/ssl/inception.crt - SSL Key:
/etc/nginx/ssl/inception.key
To modify:
- Edit
roles/nginx/files/nginx.conf - Update
server_name,root, or SSL paths as needed - Run playbook to apply changes
ansible-playbook -i inventory.ini setup.yml --ask-vault-passCreate password file:
echo "your_vault_password" > ~/.vault_pass
chmod 600 ~/.vault_passRun playbook:
ansible-playbook setup.yml --vault-password-file ~/.vault_passexport ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
ansible-playbook -i inventory.ini setup.yml# Run only base role
ansible-playbook -i inventory.ini setup.yml --tags base --ask-vault-pass
# Run only nginx
ansible-playbook -i inventory.ini setup.yml --tags nginx --ask-vault-pass
# Run only app deployment
ansible-playbook -i inventory.ini setup.yml --tags app --ask-vault-passansible-playbook -i inventory.ini setup.yml --ask-vault-pass --checkPurpose: Prepare the server for application deployment
Tasks:
- Update apt package lists (
apt update) - Upgrade all packages (
apt upgrade -y) - Install essential tools:
curl- HTTP clientgit- Version controlfail2ban- Brute-force protection
Services:
- Enables and starts
fail2ban
Location: roles/base/tasks/main.yml
Purpose: Install and configure Nginx with HTTPS support
Tasks:
- Install Nginx package
- Enable and start Nginx service
- Generate self-signed SSL certificates (CN=135.225.128.201)
- Copy custom Nginx configuration
- Restart Nginx to apply config
SSL Certificate Details:
- Type: Self-signed X.509 certificate
- Duration: 365 days
- Algorithm: RSA
- Cipher: TLS 1.3 only
- Location:
/etc/nginx/ssl/
Location: roles/nginx/tasks/main.yml
Config: roles/nginx/files/nginx.conf
Purpose: Deploy website files from tarball to web root
Tasks:
- Copy
website.zipfrom control machine to/home/myserver/ - Extract archive to
/var/www/html/ - Remove temporary zip file
- Website accessible at
https://135.225.128.201/
Expected Structure:
/var/www/html/
└── feane-1.0.0/
├── index.html
├── css/
├── js/
└── ...
Location: roles/app/tasks/main.yml
Purpose: Configure passwordless SSH access
Tasks:
- Install
sshpassutility - Copy SSH public key to server's
authorized_keys - Enable key-based authentication
Requirements:
ssh_passwordvariable in vault.yml- SSH public key in control machine (
~/.ssh/id_rsa.pub)
Location: roles/ssh/tasks/main.yml
Server Block: myserver
├── Listen: 443 (HTTPS)
├── Server Name: 135.225.128.201
├── Document Root: /var/www/html/feane-1.0.0
├── SSL Protocol: TLSv1.3
├── Certificate: /etc/nginx/ssl/inception.crt
├── Private Key: /etc/nginx/ssl/inception.key
└── Location /
├── try_files: $uri $uri/ =404
└── error_page 404: /index.html
- HTTPS Only: Requests only accepted on port 443
- File Resolution: First tries exact file, then directory
- SPA Support: 404 errors redirected to
index.html(single-page app) - Certificate Warning: Self-signed cert will trigger browser warning
- Click "Advanced" → "Proceed" to continue
https://135.225.128.201/
✅ DO:
- Encrypt all sensitive data in vault.yml
- Use strong vault passwords (20+ characters)
- Restrict vault password file permissions:
chmod 600 ~/.vault_pass - Store vault password securely (not in version control)
- Rotate vault passwords periodically
❌ DON'T:
- Commit vault passwords to Git
- Share vault passwords via email/chat
- Use weak passwords
- Store passwords in plaintext files
- Run playbooks with
--vault-password-filein production scripts
- Self-signed certificates: OK for testing/internal use only
- Production: Use Let's Encrypt or commercial CA certificates
- Certificate update: Modify
roles/nginx/files/nginx.conf→ rerun playbook - TLS 1.3: Current standard (TLS 1.0/1.1/1.2 deprecated)
SSH Connection Refused
fatal: [135.225.128.201]: UNREACHABLE!
Solutions:
- Verify IP address in
inventory.ini - Check SSH port (default 22)
- Ensure firewall allows port 22
- Test:
ssh -v myserver@135.225.128.201
Authentication Failed
fatal: [myserver]: FAILED! => {"msg": "unsudoers"}
Solutions:
- Verify
ssh_passwordin vault.yml is correct - Ensure user has sudo privileges:
sudo usermod -aG sudo myserver - Test:
ssh -v myserver@135.225.128.201
Vault Password Not Matching
fatal: [myserver]: FAILED! => {"msg": "Vault password did not match"}
Solutions:
- Re-enter vault password correctly
- Or use password file:
--vault-password-file ~/.vault_pass - Check file wasn't corrupted
Vault File View
# View encrypted content without decrypting
ansible-vault view group_vars/myserver/vault.yml --ask-vault-pass
# Edit vault
ansible-vault edit group_vars/myserver/vault.yml --ask-vault-passPort 443 Not Responding
# Check if nginx is listening
sudo ss -tlnp | grep 443
# Check nginx status
sudo systemctl status nginx
# View nginx error log
sudo tail -50 /var/log/nginx/error.logCertificate Not Found
# Verify SSL files exist
sudo ls -la /etc/nginx/ssl/Invalid Configuration
# Test nginx config syntax
sudo nginx -t
# Reload (if valid)
sudo systemctl reload nginx404 Errors
# Check website files exist
ls -la /var/www/html/feane-1.0.0/
# Check permissions
sudo chown -R www-data:www-data /var/www/html/
sudo chmod -R 755 /var/www/html/Test Locally on Server
curl -kv https://localhost/
curl -kv https://127.0.0.1/If HTTPS times out:
- Login to Azure Portal
- Navigate to your VM's Network settings
- Check Inbound port rules
- Ensure port 443 is allowed from "Any" or your IP
- Wait 1-2 minutes for changes to apply
# List all hosts
ansible-inventory --list
# Test connectivity
ansible -i inventory.ini all -m ping --ask-vault-pass
# Run ad-hoc command
ansible -i inventory.ini myserver -m shell -a "uptime" --ask-vault-pass
# Display facts about hosts
ansible -i inventory.ini myserver -m setup --ask-vault-pass
# Dry run (check mode)
ansible-playbook -i inventory.ini setup.yml --check --ask-vault-pass
# Increase verbosity
ansible-playbook -i inventory.ini setup.yml -vvv --ask-vault-pass
# List tasks without running
ansible-playbook -i inventory.ini setup.yml --list-tasks- Ansible Documentation
- Ansible Vault Guide
- Nginx Documentation
- HTTPS Best Practices
- Azure VM Security
https://roadmap.sh/projects/configuration-management
This project is provided as-is for infrastructure automation purposes.
Last Updated: May 5, 2026