Skip to content

Ansible Playbook for Nginx Installation and Configuration

text
nginx-ssl-playbook/
├── inventory.ini
├── playbook.yml
├── templates/
│   ├── default-site.conf.j2
│   └── ssl-params.conf.j2
└── vars/
    └── main.yml

Step 1: Create the Inventory File

Create an inventory file named inventory.ini:

ini
[webservers]
webserver ansible_host=your_server_ip ansible_user=root

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Step 2: Create Vars File

Create a vars file named vars/main.yml:

yaml
---
# Domain configuration
domain_name: "example.com"
domain_aliases:
  - "www.example.com"

# Nginx configuration
nginx_root: "/var/www/html"
nginx_index_files: "index.html index.htm index.nginx-debian.html"

# SSL configuration
ssl_email: "your-email@example.com"
ssl_auto_redirect: true

# Custom website content (optional)
custom_website_content: "<html><head><title>My Website</title></head><body><h1>Hello, World!</h1></body></html>"

Step 3: Create Template Files

Create a template file for the Nginx server block named templates/default-site.conf.j2:

jinja
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root {{ nginx_root }};
    index {{ nginx_index_files }};

    server_name {{ domain_name }} {% for alias in domain_aliases %} {{ alias }}{% endfor %};

    location / {
        try_files $uri $uri/ =404;
    }
}

Create a template file for SSL parameters named templates/ssl-params.conf.j2:

jinja
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

Step 4: Create the Playbook

Create a playbook file named playbook.yml:

yaml
---
- hosts: webservers
  become: yes
  vars_files:
    - vars/main.yml

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Upgrade packages
      apt:
        upgrade: dist

    - name: Install Nginx
      apt:
        name: nginx
        state: present
      notify: Start Nginx

    - name: Allow HTTP and HTTPS through UFW
      ufw:
        rule: allow
        name: "Nginx Full"
      register: ufw_status

    - name: Show UFW status
      command: ufw status
      register: ufw_status_result
      changed_when: false

    - name: Display UFW status
      debug:
        msg: "{{ ufw_status_result.stdout_lines }}"

    - name: Configure Nginx default site
      template:
        src: templates/default-site.conf.j2
        dest: /etc/nginx/sites-available/default
        owner: root
        group: root
        mode: "0644"
      notify: Reload Nginx

    - name: Create custom website (optional)
      copy:
        content: "{{ custom_website_content }}"
        dest: "{{ nginx_root }}/index.html"
        owner: www-data
        group: www-data
        mode: "0644"

    - name: Install Certbot
      apt:
        name:
          - certbot
          - python3-certbot-nginx
        state: present

    - name: Create SSL parameters file
      template:
        src: templates/ssl-params.conf.j2
        dest: /etc/nginx/snippets/ssl-params.conf
        owner: root
        group: root
        mode: "0644"

    - name: Check if SSL certificate exists
      stat:
        path: /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem
      register: ssl_cert

    - name: Get SSL certificate with Certbot
      shell: >
        certbot --nginx 
        -d {{ domain_name }} 
        {% for alias in domain_aliases %} -d {{ alias }}{% endfor %} 
        --non-interactive --agree-tos --email {{ ssl_email }}
        {% if ssl_auto_redirect %}--redirect{% endif %}
      when: not ssl_cert.stat.exists
      notify: Reload Nginx

    - name: Verify SSL certificate auto-renewal
      command: certbot renew --dry-run
      changed_when: false

    - name: Update default site to include SSL params
      lineinfile:
        path: /etc/nginx/sites-available/default
        regexp: "^    include snippets/ssl-params.conf;"
        insertafter: '    listen \[\:\:\]\:443 ssl;'
        line: "    include snippets/ssl-params.conf;"
      notify: Reload Nginx

  handlers:
    - name: Start Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

    - name: Reload Nginx
      systemd:
        name: nginx
        state: reloaded

    - name: Test Nginx configuration
      command: nginx -t
      register: nginx_config_test
      changed_when: false
      notify: Reload Nginx if config OK

    - name: Reload Nginx if config OK
      systemd:
        name: nginx
        state: reloaded
      when: nginx_config_test is success

Step 5: Run the Playbook

  1. Update your inventory file with the correct server IP and user.
  2. Modify the variables in vars/main.yml to match your domain and preferences.
  3. Run the playbook with the following command:
bash
ansible-playbook -i inventory.ini playbook.yml

Features

This Ansible playbook automates the following tasks:

  • Updates system packages
  • Installs and configures Nginx
  • Sets up proper firewall rules
  • Creates a default website
  • Installs and configures SSL with Certbot
  • Implements additional security hardening
  • Verifies auto-renewal of SSL certificates
  • Includes thorough error checking and handlers

Customization

To use this playbook for different servers or domains:

  1. Modify the inventory.ini file to include your target servers
  2. Update the variables in vars/main.yml with domain names and other preferences
  3. Run the playbook again to apply the configuration to new servers

All templates and configurations are parameterized to make this playbook completely reusable across different environments.