In this article, we’ll install and configure Nginx as the web server for our project. Instead of configuring everything manually, we’ll use Ansible roles to make the process repeatable and clean.
📁 Step 1: Create the Nginx Role
Let’s start by creating a new role for our Nginx configuration:
mkdir -p roles/install-nginx/{tasks,handlers,templates}
Now add the role to your main.yml
Ansible playbook:
# main.yml
...
roles:
- role: roles/security
- role: roles/install-nginx
⚙️ Step 2: Add the Base Nginx Tasks
Create roles/install-nginx/tasks/main.yml
:
---
- name: Install Nginx
apt:
name: nginx
state: present
force: yes
update_cache: yes
- name: Symlink default site
file:
src: /etc/nginx/sites-available/default
dest: /etc/nginx/sites-enabled/default
state: link
- name: Configure http ufw for nginx
ufw: rule=allow port=80 proto=tcp
- name: Configure https ufw for nginx
ufw: rule=allow port=443 proto=tcp
notify: Restart Nginx
🔍 Breaking It Down
Install Nginx: Installs the package with cache refresh.
Symlink default site: Makes sure Nginx loads the default config from sites-available
.
UFW rules: Opens ports 80
(HTTP) and 443
(HTTPS) in the firewall.
Notify handler: Triggers a service restart if configs change.
🔁 Step 3: Add the Handlers
Create the handler file:roles/install-nginx/handlers/main.yml
---
- name: Restart Nginx
service:
name: nginx
state: restarted
This ensures Nginx restarts whenever our configuration is updated.
🚀 Step 4: Run the Playbook
Run the updated playbook:
play main.yml
Then verify that Nginx is up and running:
curl <droplet ip>
You should see the default Nginx welcome page.
✍️ Step 5: Customize Nginx Configuration
- SSH into your server and copy the default config:
scp admin@<droplet-ip>:/etc/nginx/nginx.conf roles/install-nginx/templates/nginx.conf.j2
2. Edit relevant parts of the config to use Ansible variables:
user {{ username }};
worker_processes {{ cpu_count }};
username
: Already defined in our playbook vars.cpu_count
: The number of CPU cores available.
You can check your core count on the server with:
nproc
🔁 Step 6: Tune the Events Section
Update the events
block like this:
events {
worker_connections {{ worker_connections }};
multi_accept on;
}
worker_connections
: Set to your system’s open file limit:
ulimit -n
multi_accept on
: Allows a worker to accept multiple connections at once, improving performance under load.
🌀 Step 7: Add Gzip Compression
Update the http
block to include:
gzip on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
This enables compression for common static file types. Gzip reduces the size of HTTP responses and improves page load time—especially important for mobile or slower connections.
🧩 Step 8: Final nginx.conf
Template
Here’s what your final nginx.conf.j2
should look like:
user {{ username }};
worker_processes {{ cpu_count }};
worker_cpu_affinity auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections {{ worker_connections }};
multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
server_tokens build; # Recommended practice is to turn this off
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1
ssl_prefer_server_ciphers off; # Don't force server cipher order.
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
📤 Step 9: Upload the Config with Ansible
Update your role’s tasks/main.yml
to include:
...
- name: Upload nginx.conf file
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
vars:
worker_connections: 1024
cpu_count: 1
notify: Restart Nginx
Then re-run:
play main.yml
🎉 Summary
In this article, we:
- Created a reusable Ansible role for Nginx
- Installed and configured the base firewall rules
- Customized
nginx.conf
with variables likeusername
andcpu_count
- Enabled Gzip compression and multi_accept for better performance
- Verified that Nginx is working with our config
🔜 Next Up…
In the next part of the series, we’ll create a basic Flask Hello World app, serve it with Gunicorn, and integrate it into our Nginx configuration.
See you there! 👋
Leave a Reply