Ansible Web App Deployment Playbook | Generated by AI
Here’s a complete, production-ready Ansible playbook to deploy a Python web application with the exact flow you described:
Git checkout → pip install → gunicorn → nginx reverse proxy
Directory structure (recommended)
inventory.ini
deploy.yml
roles/
webapp/
tasks/
main.yml
templates/
gunicorn.service.j2
nginx-site.conf.j2
files/
(optional static files)
handlers/
main.yml
1. inventory.ini
[webservers]
app.example.com ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/yourkey.pem
[webservers:vars]
app_name=myflaskapp
app_repo=https://github.com/youruser/myflaskapp.git
app_branch=main
app_port=8000 # internal Gunicorn port
python_version=3.11
2. deploy.yml (main playbook)
---
- name: Deploy Python web application with Gunicorn + Nginx
hosts: webservers
become: yes
vars:
app_dir: /opt/
venv_dir: /opt//venv
requirements_file: "/requirements.txt"
roles:
- webapp
3. roles/webapp/tasks/main.yml
---
- name: Install system dependencies
apt:
name:
- git
- python-venv
- python
- python3-pip
- gunicorn
- nginx
state: present
update_cache: yes
- name: Create application directory
file:
path: ""
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Clone or update application from Git
git:
repo: ""
dest: ""
version: ""
force: yes
update: yes
notify: Restart gunicorn
- name: Create Python virtual environment
pip:
virtualenv: ""
virtualenv_python: python
- name: Install Python requirements
pip:
requirements: ""
virtualenv: ""
notify: Restart gunicorn
- name: Copy Gunicorn systemd service
template:
src: gunicorn.service.j2
dest: /etc/systemd/system/.service
mode: '0644'
notify:
- Reload systemd
- Restart gunicorn
- name: Enable and start Gunicorn service
systemd:
name: ""
enabled: yes
state: started
daemon_reload: yes
- name: Configure Nginx reverse proxy
template:
src: nginx-site.conf.j2
dest: /etc/nginx/sites-available/
mode: '0644'
notify: Reload nginx
- name: Enable Nginx site
file:
src: /etc/nginx/sites-available/
dest: /etc/nginx/sites-enabled/
state: link
notify: Reload nginx
- name: Remove default Nginx site (optional)
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload nginx
4. roles/webapp/templates/gunicorn.service.j2
[Unit]
Description=Gunicorn instance for
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=
Environment="PATH=/bin"
ExecStart=/bin/gunicorn --workers 3 --bind unix:/run/.sock app:app
# or use your wsgi entrypoint, e.g.: main:app or wsgi:app
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
5. roles/webapp/templates/nginx-site.conf.j2
server {
listen 80;
server_name _; # or your domain: app.example.com
location / {
include proxy_params;
proxy_pass http://unix:/run/.sock;
}
location /static/ {
alias /static/;
}
# Optional: serve media files
# location /media/ {
# alias /media/;
# }
}
6. roles/webapp/handlers/main.yml
---
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Restart gunicorn
systemd:
name: ""
state: restarted
- name: Reload nginx
service:
name: nginx
state: reloaded
Run the deployment
ansible-playbook -i inventory.ini deploy.yml
Subsequent deployments (zero-downtime)
Just run the same command again. Git pull + pip install will trigger Gunicorn restart automatically thanks to the handlers.
Optional improvements
- Add
--collect-staticfor Django - Add SSL with Certbot (separate role)
- Use
supervisorinstead of systemd if preferred - Add health checks and rollback capabilities
This playbook is idempotent, secure (runs as www-data), and used in many production environments.