If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeLet's tackle one of the most confusing things in Symfony: how to handle file permissions for the cache directory.
To get our site working, we're setting the entire var/
directory to 777:
... lines 1 - 40 | |
- name: Setup directory permissions for var/ | |
file: | |
path: "{{ release_var_path }}" | |
state: directory | |
mode: 0777 | |
recurse: true | |
# We need it because logs are symlinks now | |
follow: yes |
This includes cache/
, logs/
and sessions/
.
This is a bummer for security. Here's my big question: after we deploy, which files truly need to be writable by the web server?
Let's solve this ancient Symfony mystery. To start, instead of setting the entire var/
directory to 777, let's just do this for var/logs
. This is actually the reason we originally created this task: our site was failing because var/logs
wasn't writable.
But first, back in deploy.yml
, create a new variable: release_logs_path
set to {{ ansistrano_shared_path }}/var/logs
:
- hosts: aws | |
... lines 3 - 14 | |
vars: | |
... lines 16 - 17 | |
release_logs_path: "{{ ansistrano_shared_path }}/var/logs" | |
... lines 19 - 56 |
ansistrano_shared_path
is a special variable that Ansistrano gives us. Thanks!
Copy that variable, and back in after-symlink-shared.yml
, use it:
... lines 1 - 40 | |
- name: Setup directory permissions for var/logs | |
become: true | |
file: | |
path: '{{ release_logs_path }}' | |
state: directory | |
mode: 0777 | |
recurse: true |
Oh, and we don't need follow
anymore. But do add become: true
. Why? The files in this directory - like prod.log
- will probably be created by the web server, so, www-data
. The become: true
will allow us to change those permissions.
Ok, let's try this! Find your local terminal, and deploy!
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --ask-vault-pass
When this finishes, only var/logs/
should be writable.
Deep breath. Refresh! Dang! It fails! That's ok! Let's play detective and uncover the problem.
Back on the server, find the var/logs
directory and tail prod.log
:
cd shared/var/logs
tail prod.log
Oh!
Unable to create the directory
var/sessions
Apparently the var/sessions
directory needs to be writable so that the session data can be stored.
But wait! Before we make that writable, I have a better solution. Open up app/config/config.yml
. Look under framework
and session
:
... lines 1 - 10 | |
framework: | |
... lines 12 - 26 | |
session: | |
# http://symfony.com/doc/current/reference/configuration/framework.html#handler-id | |
handler_id: session.handler.native_file | |
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%' | |
... lines 31 - 72 |
Ah! This is the reason why sessions are stored in var/sessions
. Change that: set handler_id
to ~
. I'll add a comment: this means that the default PHP session handler will be used:
... lines 1 - 10 | |
framework: | |
... lines 12 - 26 | |
session: | |
# use the default PHP session handler | |
handler_id: ~ | |
... lines 30 - 71 |
Why are we doing this? Well, PHP already knows how to handle and store sessions. It will find a directory on the file system to store them and it will handle permissions... because making them 777 isn't a great idea. In fact, this will be the default setting for new Symfony 4 projects.
Go back to the local terminal. We just made a change to our code, so we need to commit and push:
git add -u
git commit -m "PHP native sessions"
git push origin master
Now, deploy!
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --ask-vault-pass
An even better session setup - especially if you want to move servers or use multiple servers - is to store them somewhere else, like the database or Memcache. You can find details about that in the Symfony docs. That's what we do for KnpU.
Ok! Let's try it again.. refresh! It works! OMG, it's alive! So... does this mean that the var/cache
directory does not need to be writable? Well... not so fast. Go back to the server. Move up a few directories and into current/
. Check out the var/cache/prod
directory:
ls -l var/cache/prod
Woh! The cache files are writable by everyone! And so of course the site is working! But... we didn't set the cache directory to 777 in our playbook? So, what's going on?
We still have two unanswered questions. First, why the heck is var/cache/prod/
writable by everyone? And second, if we make it not writable, will our site still work?
Let's solve these mysteries next.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=5.5.9",
"doctrine/doctrine-bundle": "^1.6", // 1.6.8
"doctrine/orm": "^2.5", // v2.7.2
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"sensio/distribution-bundle": "^5.0.19", // v5.0.20
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
"symfony/monolog-bundle": "^3.1.0", // v3.1.0
"symfony/polyfill-apcu": "^1.0", // v1.4.0
"symfony/swiftmailer-bundle": "^2.3.10", // v2.6.3
"symfony/symfony": "3.3.*", // v3.3.5
"twig/twig": "^1.0||^2.0", // v1.34.4
"doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.1
"predis/predis": "^1.1", // v1.1.1
"composer/package-versions-deprecated": "^1.11" // 1.11.99
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.6
"symfony/phpunit-bridge": "^3.0", // v3.3.5
"doctrine/data-fixtures": "^1.1", // 1.3.3
"hautelook/alice-bundle": "^1.3" // v1.4.1
}
}
# ansible/requirements.yml
-
src: DavidWittman.redis
version: 1.2.4
-
src: ansistrano.deploy
version: 2.7.0
-
src: ansistrano.rollback
version: 2.0.1