Fully automated deployment of a production-ready LAMP (Linux, Apache, MySQL, PHP) stack using Ansible.
- ✅ Apache2 web server with virtual hosts
- ✅ MySQL 8.0 database with secure configuration
- ✅ PHP 8.1 with common extensions
- ✅ UFW firewall configuration
- ✅ SSL/TLS certificate support
- ✅ Automated backups
- ✅ Health checks and monitoring
# Install dependencies
ansible-galaxy install -r requirements.yml
# Update inventory
nano inventory/hosts
# Run playbook
ansible-playbook site.yml --vault-password-file .vault_pass.
├── ansible.cfg
├── site.yml
├── healthcheck.yml
├── backup.yml
├── rollback.yml
├── maintenance.yml
├── test.yml
├── Makefile
├── inventory/
│ └── hosts
├── group_vars/
│ ├── all.yml
│ ├── webservers.yml
│ ├── databases.yml
│ └── vault.yml (encrypted)
├── roles/
│ ├── common/
│ │ ├── tasks/
│ │ ├── handlers/
│ │ └── defaults/
│ ├── apache/
│ │ ├── tasks/
│ │ ├── handlers/
│ │ └── templates/
│ ├── mysql/
│ │ ├── tasks/
│ │ ├── handlers/
│ │ └── templates/
│ └── php/
│ ├── tasks/
│ ├── handlers/
│ └── templates/
├── README.md
├── DEPLOYMENT.md
└── .gitignore
- Ansible 2.9+
- Ubuntu 20.04/22.04 target servers
- SSH access to target servers
- Python 3.6+ on control node
git clone https://github.com/George-Nyamao/ansible-lamp-stack.git
cd ansible-lamp-stackEdit inventory/hosts with your server details:
[webservers]
web1 ansible_host=192.168.1.10 ansible_user=ubuntu
[databases]
db1 ansible_host=192.168.1.20 ansible_user=ubuntuecho "your-strong-vault-password" > .vault_pass
chmod 600 .vault_passImportant: Never commit .vault_pass to version control!
Edit the following files in group_vars/:
group_vars/all.yml:
app_name: "myapp"
app_domain: "example.com"
timezone: "UTC"group_vars/webservers.yml:
apache_listen_port: 80
php_version: "8.1"
php_memory_limit: "256M"group_vars/databases.yml:
mysql_version: "8.0"
mysql_port: 3306ansible-vault edit group_vars/vault.yml --vault-password-file .vault_passUpdate these variables:
vault_mysql_root_password: "YourSecureRootPassword"
vault_app_db_password: "YourSecureAppPassword"# Check syntax
make check
# Deploy full stack
make deploy
# Run tests
make test
# Health check
make health
# Backup
make backup# Syntax check
ansible-playbook site.yml --syntax-check
# Dry run
ansible-playbook site.yml --check --vault-password-file .vault_pass
# Deploy
ansible-playbook site.yml --vault-password-file .vault_pass
# Deploy specific components
ansible-playbook site.yml --tags "apache,php" --vault-password-file .vault_pass
# Run health checks
ansible-playbook healthcheck.yml
# Run tests
ansible-playbook test.yml --vault-password-file .vault_pass
# Backup
ansible-playbook backup.yml --vault-password-file .vault_passAfter successful deployment:
- Main Website:
http://YOUR_SERVER_IPorhttp://your-domain.com - PHP Info:
http://YOUR_SERVER_IP/info.php - Database Test:
http://YOUR_SERVER_IP/db_test.php
ansible webservers -m file -a "path=/var/www/example.com/html/info.php state=absent" --become
ansible webservers -m file -a "path=/var/www/example.com/html/db_test.php state=absent" --become# Install Certbot
ansible webservers -m apt -a "name=certbot,python3-certbot-apache state=present" --become
# Obtain certificate (replace with your domain)
ansible webservers -m shell -a "certbot --apache -d example.com -d www.example.com --non-interactive --agree-tos --email admin@example.com" --becomeansible-playbook maintenance.yml -e "maintenance_action=update" --vault-password-file .vault_passansible-playbook maintenance.yml -e "maintenance_action=restart" --vault-password-file .vault_passansible-playbook maintenance.yml -e "maintenance_action=cleanup" --vault-password-file .vault_passAutomated backups run daily at 2 AM. For manual backup:
make backup
# or
ansible-playbook backup.yml --vault-password-file .vault_pass# Apache status
ansible webservers -m shell -a "systemctl status apache2" --become
# MySQL status
ansible databases -m shell -a "systemctl status mysql" --become
# PHP version
ansible webservers -m shell -a "php -v" --becomemake health
# or
ansible-playbook healthcheck.yml# Apache error logs
ansible webservers -m shell -a "tail -50 /var/log/apache2/error.log" --become
# Apache access logs
ansible webservers -m shell -a "tail -50 /var/log/apache2/access.log" --become
# MySQL error logs
ansible databases -m shell -a "tail -50 /var/log/mysql/error.log" --become
# PHP error logs
ansible webservers -m shell -a "tail -50 /var/log/php_errors.log" --become# Check disk space
ansible lamp -m shell -a "df -h" --become
# Check memory usage
ansible lamp -m shell -a "free -h" --become
# Check CPU usage
ansible lamp -m shell -a "top -bn1 | head -20" --become# Test connectivity
ansible lamp -m ping
# Test SSH
ansible lamp -m shell -a "echo 'Connection successful'"# Restart Apache
ansible webservers -m systemd -a "name=apache2 state=restarted" --become
# Restart MySQL
ansible databases -m systemd -a "name=mysql state=restarted" --become
# Check service status
ansible lamp -m shell -a "systemctl list-units --type=service --state=running | grep -E 'apache|mysql'" --become# Test MySQL connection from web server
ansible webservers -m shell -a "mysql -h DB_SERVER_IP -u appuser -p'password' -e 'SHOW DATABASES;'" --become
# Check MySQL port
ansible databases -m shell -a "netstat -tlnp | grep 3306" --become# Fix web directory permissions
ansible webservers -m file -a "path=/var/www/example.com/html owner=www-data group=www-data recurse=yes" --becomeIf deployment fails or issues occur:
make rollback
# or
ansible-playbook rollback.yml --vault-password-file .vault_passRun comprehensive tests:
make test
# or
ansible-playbook test.yml --vault-password-file .vault_passTests include:
- Service status verification
- HTTP response checks
- Database connectivity
- PHP functionality
- Configuration validation
- Strong Passwords: Use complex passwords (20+ characters with special characters)
- Firewall: UFW is configured automatically - review rules regularly
- Regular Updates: Run weekly security updates
- Remove Test Files: Delete
info.phpanddb_test.phpin production - SSL/TLS: Always use HTTPS in production
- Database Access: Restrict MySQL to specific IPs
- Backup Verification: Test backups regularly
- Log Monitoring: Check logs for suspicious activity
- Principle of Least Privilege: Use minimal required permissions
- Security Headers: Already configured in Apache
# Deploy everything
make deploy
# Deploy only Apache
ansible-playbook site.yml --tags apache --vault-password-file .vault_pass
# Deploy only MySQL
ansible-playbook site.yml --tags mysql --vault-password-file .vault_pass
# Deploy only PHP
ansible-playbook site.yml --tags php --vault-password-file .vault_pass
# Run health checks
make health
# View all hosts
ansible lamp --list-hosts
# Gather facts
ansible lamp -m setup --tree /tmp/facts
# Ad-hoc command execution
ansible lamp -m shell -a "uptime" --becomeEdit group_vars/webservers.yml:
apache_mods_enabled:
- rewrite
- ssl
- headers
- expires
- deflate # Enable compression
- cache # Enable cachingEdit group_vars/databases.yml:
mysql_innodb_buffer_pool_size: "2G" # Adjust based on RAM
mysql_max_connections: 500Edit group_vars/webservers.yml:
php_memory_limit: "512M"
php_max_execution_time: "300"
php_opcache_enable: 1- Edit
roles/apache/templates/vhost.conf.j2 - Add domain to
group_vars/webservers.yml - Re-run playbook
Edit roles/php/tasks/main.yml and add to the package list:
- php{{ php_version }}-imagick
- php{{ php_version }}-soap
- php{{ php_version }}-ldapCreate custom configuration in roles/mysql/templates/ and reference in tasks.
name: Deploy LAMP Stack
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Ansible
run: |
sudo apt update
sudo apt install -y ansible
- name: Deploy
run: |
echo "${{ secrets.VAULT_PASSWORD }}" > .vault_pass
ansible-playbook site.yml --vault-password-file .vault_pass
env:
ANSIBLE_HOST_KEY_CHECKING: FalseContributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE file for details
- Documentation: See DEPLOYMENT.md for detailed deployment guide
- Issues: Report issues on GitHub Issues
- Discussions: Join discussions on GitHub Discussions
- Initial release
- Complete LAMP stack automation
- Backup and rollback functionality
- Comprehensive testing suite
- Security hardening
George Nyamao
- GitHub: George-Nyamao
- LinkedIn: George Nyamao
- Email: gmnyamao@hotmail.com
- Ansible community for excellent documentation
- Contributors who helped improve this project
⭐ Star this repository if you find it helpful!