Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

How to setup an Nginx webserver using Ansible on Ubuntu

profile picture
Author
Sergiu Chilat
Published
2025-01-16
Time to read
6 minutes reading time

About the author- IT enthusiast for almost 20 years:)

Introduction

This tutorial is for beginner DevOps enthusiasts and it illustrate how to simply setup an Nginx web server, install Docker and DockerCompose, and configure a Let’s Encrypt certificate managed by Certbot. The proposed solution is based on Ansible playbooks.

Prerequisites

  • A local device
  • A remote VPS instance with Ubuntu (see this getting started)
    • Add the public key of your local device to your remote VPS. You can find a simple tutorial here.

Before you start

Before you start, make sure you have the following files and directories:

ansible-project/
├── ansible.cfg      # Ansible configuration file
├── inventory        # Ansible inventory
├── env.yml          # Environment variables
└── playbooks/       # Directory for the playbooks that will be added in the steps below
  • ~/ansible-project/ansible.cfg

    Here you can set the inventory file that Ansible will use by default when running the playbooks.

    [defaults]
    inventory = inventory
  • ~/ansible-project/inventory

    Here you can add the IP addresses of the servers that you want to configure.

    [all]
    127.0.0.1
    127.0.0.2
    127.0.0.3
  • ~/ansible-project/env.yml

    This project uses some variables that are stored in the env.yml file that is imported in all playbooks.

    APP_MAIN_DOMAIN: "example.com"
    LETS_ENCRYPT_EMAIL: "your_email@mail.com"
    NGINX_MAX_BODY_SIZE: "50M"
    TIMEZONE: "Europe/Chisinau"
    • APP_MAIN_DOMAIN: example.com - the main domain that will be used for the server
    • LETS_ENCRYPT_EMAIL: your_email@example.com - the email that will be used for the Let's Encrypt certificate generation
    • NGINX_MAX_BODY_SIZE: 50M - the maximum body size that Nginx will accept
    • TIMEZONE: Europe/Chisinau - the timezone that will be set on the server
  • ~/ansible-project/playbooks

    Create a directory for the playbooks.

Step 1 - Configure the web sever

In this sample the timezone of the server is set to the TIMEZONE variable. This playbook can be extended to set other configurations as well, depending on your needs.

~/ansible-project/playbooks/configure-server.yml

- name: Set the system timezone
  hosts: all
  become: yes
  user: root

  vars_files:
    - ../env.yml

  tasks:
    - name: Set timezone
      ansible.builtin.command:
        cmd: timedatectl set-timezone {{ TIMEZONE }}

Step 2 - Install and configure Nginx

In this step we will install Nginx and configure it to serve the main domain. Below is the code that will install Nginx and configure it to accept a maximum body size of 50M.

~/ansible-project/playbooks/install-nginx.yml

- name: Install Nginx
  hosts: all
  become: yes
  user: root

  vars_files:
    - ../env.yml

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

    - name: Install nginx
      apt:
        name: nginx
        state: latest

    - name: Ensure client_max_body_size is set inside the HTTP block
      ansible.builtin.blockinfile:
        path: /etc/nginx/nginx.conf
        marker: "# {mark} ANSIBLE MANAGED BLOCK"
        block: |
          client_max_body_size {{ NGINX_MAX_BODY_SIZE }};
        insertafter: '^http\s*{'
        backup: yes

    - name: Reload Nginx to apply changes
      ansible.builtin.systemd:
        name: nginx
        state: reloaded

Step 3 - Install Docker and Docker Compose

The following code will install Docker and Docker compose to your server.

~/ansible-project/playbooks/install-docker.yml

- name: Install Docker on Ubuntu
  hosts: all
  remote_user: root
  become: true
  vars:
    arch_mapping:  # Map ansible architecture {{ ansible_architecture }} names to Docker's architecture names
      x86_64: amd64
      aarch64: arm64

  tasks:
    - name: Update and upgrade all packages to the latest version
      ansible.builtin.apt:
        update_cache: true
        upgrade: dist
        cache_valid_time: 3600

    - name: Install required packages
      ansible.builtin.apt:
        pkg:
          - apt-transport-https
          - ca-certificates
          - curl
          - gnupg
          - software-properties-common

    - name: Create directory for Docker's GPG key
      ansible.builtin.file:
        path: /etc/apt/keyrings
        state: directory
        mode: '0755'

    - name: Add Docker's official GPG key
      ansible.builtin.apt_key:
        url: https://download.docker.com/linux/ubuntu/gpg
        keyring: /etc/apt/keyrings/docker.gpg
        state: present

    - name: Print architecture variables
      ansible.builtin.debug:
        msg: "Architecture: {{ ansible_architecture }}, Codename: {{ ansible_lsb.codename }}"

    - name: Add Docker repository
      ansible.builtin.apt_repository:
        repo: >-
          deb [arch={{ arch_mapping[ansible_architecture] | default(ansible_architecture) }}
          signed-by=/etc/apt/keyrings/docker.gpg]
          https://download.docker.com/linux/ubuntu {{ ansible_lsb.codename }} stable
        filename: docker
        state: present

    - name: Install Docker and related packages
      ansible.builtin.apt:
        name: "{{ item }}"
        state: present
        update_cache: true
      loop:
        - docker-ce
        - docker-ce-cli
        - containerd.io
        - docker-buildx-plugin
        - docker-compose-plugin

    - name: Add Docker group
      ansible.builtin.group:
        name: docker
        state: present

    - name: Add user to Docker group
      ansible.builtin.user:
        name: "{{ ansible_user }}"
        groups: docker
        append: true

    - name: Enable and start Docker services
      ansible.builtin.systemd:
        name: "{{ item }}"
        enabled: true
        state: started
      loop:
        - docker.service
        - containerd.service

Step 4 - Install Certbot and configure Let’s Encrypt certificate

~/ansible-project/playbooks/install-certbot.yml

The following code will install Certbot and configure a Let's Encrypt certificate for the main domain.


- name: Secure the site with Let's Encrypt
  hosts: all
  become: true
  user: root

  vars_files:
    - ../env.yml

  vars:
    webroot_path: '/var/www/html'  # the root path of your site
    certbot_source_directory: /usr/local/certbot-src
    certbot_executable_path: "{{ certbot_source_directory }}/venv/bin/certbot"
    email: "{{ LETS_ENCRYPT_EMAIL }}"
    domain: "{{ APP_MAIN_DOMAIN }}"

  tasks:
    - name: Install required packages for certbot
      ansible.builtin.apt:
        name:
          - python3
          - python3-venv
          - gcc
          - libaugeas0
          - libssl-dev
          - libffi-dev
          - ca-certificates
          - openssl
          - git

    - name: Clone the certbot source directory
      ansible.builtin.git:
        depth: 1
        repo: https://github.com/certbot/certbot
        dest: "{{ certbot_source_directory }}"
        update: true

    - name: Create certbot in virtual environment
      ansible.builtin.command: python3 tools/venv.py
      args:
        chdir: "{{ certbot_source_directory }}"

    - name: Generate the SSL certificate
      ansible.builtin.command: "{{ certbot_executable_path }} --nginx -d {{ domain }} --non-interactive --agree-tos --email {{ email }}"

    - name: Set up automatic renewal
      ansible.builtin.cron:
        name: "Certbot automatic renewal"
        job: "{{ certbot_executable_path }} renew --quiet"
        minute: "11"
        hour: "11"

You can find the variables used in this playbook in the env.yml file:

  • LETS_ENCRYPT_EMAIL - the email that will be used for the Let's Encrypt certificate generation
  • APP_MAIN_DOMAIN - the main domain that will be used for the server and the Let's Encrypt certificate

Step 5 - Run the playbooks

To run the playbooks, execute the following commands:

cd ~/ansible-project
ansible-playbook ~/ansible-project/playbooks/configure-server.yml
ansible-playbook ~/ansible-project/playbooks/install-nginx.yml
ansible-playbook ~/ansible-project/playbooks/install-docker.yml
ansible-playbook ~/ansible-project/playbooks/install-certbot.yml

After running the playbooks, you should have a web server running Nginx, Docker, Docker Compose and a Let's Encrypt certificate. You can find the Let's Encrypt certificate on the remote VPS instance in /etc/letsencrypt/live/example.com.

Conclusion

This tutorial is a simple way to setup a web server using Ansible playbooks. The playbooks can be extended to include more configurations and services.

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue

Discover our

Dedicated Servers

Configure your dream server. Top performance with an excellent connection at an unbeatable price!

Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more