Nginx Configuration & Ansible Templates
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Nginx is still using its generic, boring, but very polite default HTML page:
You're welcome for using Nginx!
It's time to point Nginx at our code! Google for "Symfony Nginx" to find a documentation page about Configuring a Web Server.
Scroll down to the Nginx section: it has a great block of Nginx config that'll work with our app. Here's the trick: we somehow need to put this configuration up onto the server and customize it. How can we do that?
Ansible does have a module for copying files from your local machine to the remote
host. But in this case, there's a different module that's even more perfect:
the template
module. It says:
Templates a file out to a remote server
In normal-person English, this means that it executes a file through Jinja - allowing us to print dynamic variables - and then copies it up to the remote server. I love this module.
Create a templates/
directory and inside, a symfony.conf
file. Paste in the
raw Nginx configuration:
server { | |
server_name domain.tld www.domain.tld; | |
root /var/www/project/web; | |
location / { | |
# try to serve file directly, fallback to app.php | |
try_files $uri /app.php$is_args$args; | |
} | |
# DEV | |
# This rule should only be placed on your development environment | |
# In production, don't include this and don't deploy app_dev.php or config.php | |
location ~ ^/(app_dev|config)\.php(/|$) { | |
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock; | |
fastcgi_split_path_info ^(.+\.php)(/.*)$; | |
include fastcgi_params; | |
# When you are using symlinks to link the document root to the | |
# current version of your application, you should pass the real | |
# application path instead of the path to the symlink to PHP | |
# FPM. | |
# Otherwise, PHP's OPcache may not properly detect changes to | |
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 | |
# for more information). | |
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; | |
fastcgi_param DOCUMENT_ROOT $realpath_root; | |
} | |
# PROD | |
location ~ ^/app\.php(/|$) { | |
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock; | |
fastcgi_split_path_info ^(.+\.php)(/.*)$; | |
include fastcgi_params; | |
# When you are using symlinks to link the document root to the | |
# current version of your application, you should pass the real | |
# application path instead of the path to the symlink to PHP | |
# FPM. | |
# Otherwise, PHP's OPcache may not properly detect changes to | |
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 | |
# for more information). | |
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; | |
fastcgi_param DOCUMENT_ROOT $realpath_root; | |
# Prevents URIs that include the front controller. This will 404: | |
# http://domain.tld/app.php/some-path | |
# Remove the internal directive to allow URIs like this | |
internal; | |
} | |
# return 404 for all other php files not matching the front controller | |
# this prevents access to other php files you don't want to be accessible. | |
location ~ \.php$ { | |
return 404; | |
} | |
error_log /var/log/nginx/project_error.log; | |
access_log /var/log/nginx/project_access.log; | |
} |
Now, a few things need to change in here. Like, server_name
should be mootube.l
and root
should point to the correct directory. Actually, root
is already correct
by chance... but we can do better!
Variables in your Template
All variables available in your playbook are available in a template. So at the
top of our playbook, let's add a few more: server_name: mootube.l
and
symfony_web_dir
set to {{ symfony_root_dir }}/web
:
- hosts: vb | |
vars: | |
server_name: mootube.l | |
symfony_root_dir: /var/www/project | |
symfony_web_dir: "{{ symfony_root_dir }}/web" | |
// ... lines 8 - 137 |
The web
directory is our document root.
Let's put those variables to work! First, use {{ server_name }}
and then set the
root to {{ symfony_web_dir }}
:
server { | |
server_name {{ server_name }}; | |
root {{ symfony_web_dir }}; | |
// ... lines 4 - 53 | |
} |
At the bottom, tweak the logs paths - instead of the word project
, use {{ server_name }}
.
Do it for the access_log
too:
server { | |
// ... lines 2 - 51 | |
error_log /var/log/nginx/{{ server_name }}_error.log; | |
access_log /var/log/nginx/{{ server_name }}_access.log; | |
} |
Oh, and while we're here, see those php5-fpm
references? Change them to php7.1-fpm.sock
in both places. FPM will already be configured to put its sock file here:
server { | |
// ... lines 2 - 11 | |
location ~ ^/(app_dev|config)\.php(/|$) { | |
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock; | |
// ... lines 14 - 24 | |
} | |
# PROD | |
location ~ ^/app\.php(/|$) { | |
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock; | |
// ... lines 29 - 43 | |
} | |
// ... lines 45 - 53 | |
} |
Using the template Module
Let's add our task to use the template: "Add Symfony config template to the Nginx
available sites". Add become: true
and use the template
module:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 46 | |
- name: Add Symfony config template to the Nginx available sites | |
become: true | |
template: | |
// ... lines 50 - 137 |
The two important options are dest
and src
. Set src
to, well templates/symfony.conf
,
and dest
to /etc/nginx/sites-available/{{ server_name }}.conf
:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 46 | |
- name: Add Symfony config template to the Nginx available sites | |
become: true | |
template: | |
src: templates/symfony.conf | |
dest: "/etc/nginx/sites-available/{{ server_name }}.conf" | |
// ... lines 52 - 137 |
Enabling the Nginx Site
Cool! Once it's in that directory, we need to enable it... which means we need to
create a symbolic link from sites-enabled
to that file in sites-available
.
And we already know the perfect module for this: file
!
Add the new task: "Enable Symfony config template from Nginx available sites".
We still need become: true
and use the file
module:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 46 | |
- name: Add Symfony config template to the Nginx available sites | |
// ... lines 48 - 52 | |
- name: Enable Symfony config template from Nginx available sites | |
become: true | |
file: | |
// ... lines 56 - 137 |
This time, for src
, copy the sites-available
line from dest
above. For dest
,
just change it to sites-enabled
:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 46 | |
- name: Add Symfony config template to the Nginx available sites | |
// ... lines 48 - 52 | |
- name: Enable Symfony config template from Nginx available sites | |
become: true | |
file: | |
src: "/etc/nginx/sites-available/{{ server_name }}.conf" | |
dest: "/etc/nginx/sites-enabled/{{ server_name }}.conf" | |
state: link | |
// ... lines 59 - 137 |
To create the symbolic link, use state: link
. Earlier we created a directory
with state: directory
.
Updating /etc/hosts
The last thing I'll do - which is optional - is to add a task named
"Add enabled Nginx site /etc/hosts". I'll use lineinfile
to modify /etc/hosts
and look for a line that contains {{ server_name }}
. Then, I'll replace it with
127.0.0.1 {{ server_name }}
:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 52 | |
- name: Enable Symfony config template from Nginx available sites | |
// ... lines 54 - 59 | |
- name: Add enabled Nginx site to /etc/hosts | |
become: true | |
lineinfile: | |
dest: /etc/hosts | |
regexp: "{{ server_name }}" | |
line: "127.0.0.1 {{ server_name }}" | |
// ... lines 66 - 137 |
This will guarantee that we have a /etc/hosts
entry for mootube.l
that points
to 127.0.0.1
inside the VM. It's not a big deal - but it'll let us refer to mootube.l
in the VM.
Of course, the first time this runs, it will not find a line in that file that matches
mootube.l
. But that's no problem: lineinfile
will guarantee that the line
value exists by adding it at the bottom.
Before you try this, make sure you have sites-available
and sites-enabled
:
- hosts: vb | |
// ... lines 3 - 8 | |
tasks: | |
// ... lines 10 - 46 | |
- name: Add Symfony config template to the Nginx available sites | |
// ... line 48 | |
template: | |
// ... line 50 | |
dest: "/etc/nginx/sites-available/{{ server_name }}.conf" | |
// ... line 52 | |
- name: Enable Symfony config template from Nginx available sites | |
// ... line 54 | |
file: | |
src: "/etc/nginx/sites-available/{{ server_name }}.conf" | |
dest: "/etc/nginx/sites-enabled/{{ server_name }}.conf" | |
// ... lines 58 - 137 |
Ok, run it!
ansible-playbook ansible/playbook.yml -i ansible/hosts.ini
Woohoo! No errors! Let's check it out! First, the file does live in sites-available/
.
And yea, awesome! The variables inside worked. Our sites-enabled
directory does
have the link, and /etc/hosts
has our new mootube.l
line at the bottom:
# /etc/hosts
# ...
127.0.0.1 mootube.l
Wow, we just killed it!
So, in theory, we should be able to go to our browser and refresh http://mootube.l
to see our site. Refresh! Um.... we still see the same, boring - but polite - Nginx
Configuration page.
Why? Some of you are probably screaming the answer at your computer... and also scaring your co-workers. It's because, we have not restarted or reloaded Nginx. Yea, this is easy to do manually - but come on! We need to teach our playbook to know when Nginx - and also PHP FPM - need to be restarted. We can do that with... handlers!
Are there updates to this script for symfony4 and php7.3?
I can't get the site to work, despite changing the pointers to php7.3 and /public?!
Also, my site downloads any php files if i browse directly to them instead of serving them? What needs to change on this script?
Cheers,
Jason.