How to keep PHP updated with last patch version on Ubuntu
Every year people at packagist share some insightful stats about usage of php. Adoption of new major releases seems great, but here is an overview of repartitions through minor versions :
If I read this right, I found that around 70% of all those requests were made with an outdated php version ; I mean that weren’t upgraded with latest patch. For example in this dataset, there is more people using 7.2.24 than 7.2.27. It is a bit of a shortcut, but considering that the vast majority of web servers are using php, that makes a lot of outdated php engines out there ! And obviously outdated means more bugs and a serious lack of security. New vulnerabilities are probably more common than you think.
So why is that ? What is causing this lack of upgrade ? Automation ! Instead of being automated, this task is generally done manually, if not at all.
As a web developer, sysadmin is far from my comfort zone ; Disclaimer: I’m not an expert. My code is still running on good old VPS handled by laravel forge. This tool is a relief to setup a new plateform, but unfortunately it doesn’t help with upgrading php automatically. It has a really nice feature to help you doing it smoothly though.
I made some research on the subject, and found a lot of resources and tutorials. All of them focus on installing php or upgrading to a specific major version, but always forget to say how to keep it up to date. I finally found it myself, but my “newbie” journey was far from easy. I focused on Ubuntu because unfortunately it is totally different on others systems. Anyway I sincerely hope it’ll help someone.
Installing a major version
As said before, the subject of installing php is super well documented. You’ll find everything easily. But while connecting to remote plateform you sometimes need to check what’s already installed. This is how I would do that.
List all php major versions installed
Before installing or removing a php version, I like to list what’s already installed. It is also very useful because it includes extensions.
dpkg --list | grep php
Each version of ubuntu comes with only one packaged php version (for example, ubuntu 18.04 comes with php 7.2). If you want to be able to install another one, you’ll probably need a PPA (Personnal Package Archive). A nice guy named Ondřej provides a popular one for ubuntu (please consider sponsoring him if you can on patreon or github).
sudo add-apt-repository ppa:ondrej/php
Also, you can list anytime all configured PPAs on your system.
sed -n '/deb .*ppa.launchpad.net/ s@.*ppa.launchpad.net/\(.*\)/ubuntu.*@\1@p' /etc/apt/sources.list.d/*.list
Prevent a newer major php version from being installed
This step is not mandatory but it can be useful, if you’re not ready to upgrade yet to the last major version and want to keep running on an older one. You can prevent a given php version from being installed on your system. You can note the use of an
* at the end, its purpose is to include extensions.
sudo apt-mark hold php7.4*
You can also view all your held packages by running:
Of course, when you’re ready to upgrade to a new major version, the hold will need to be removed. It can be reversed by unholding all php packages:
sudo apt-mark unhold php7.4*
Keeping PHP up to date
Now that you have installed everything, you’re all set and it’s all good. But not for long, because a new patch will be available sooner than you think.
Obviously, the simplest way to achieve this, is to manually upgrade php. You’ll need to check for new release yourself, and running this command manually on each of your servers. Managing a large number of them could be a pain.
sudo apt-get install --only-upgrade php7.4*
Bonus: You can easily setup a notification system to help you keep track of outdated servers even with methods as convenient as slack notifications in a dedicated channel.
We finally get to the whole point of this post. How can we get our system to upgrade php on its own ? With a tool called: unattended-upgrades. In fact, you probably already have it installed and running, upgrading your system on a regular basis. But since you get php from a PPA, it just doesn’t work out of the box.
So you’ll need to tell the program explicitly to do it for a given PPA. Because it would have been too easy, you’ll need to know :
- your distribution’s codename.
- the PPA “origin”
When using Ubuntu 18.04, your distribution has the nice name of “bionic”.
Then you’ll need to dig into /var/lib/apt/lists/. There I found a file called ppa.launchpad.net_ondrej_php_ubuntu_dists_bionic_InRelease. Inside I found the precious string of the ondrej PPA’s origin:
Label: ***** The main PPA for supported PHP versions with many PECL extensions *****
Now we can edit unattended-upgrades’s configuration. Just edit /etc/apt/apt.conf.d/50unattended-upgrades and add the following:
It is possible to use something a little more generic with an available macro:
Ok, we’re close, but … we’re not finished yet.
Avoiding the config file conflict resolution prompt
Every time it must install a new config file that you have modified, it will stop the upgrade, open a prompt and wait for your answer. It just want to know if you want to keep the existing conf or replace it. As you could imagine, by default “unattended-upgrades” doesn’t know how to deal with this, and it just aborts the process.
In order to keep original config files while doing automatic updates, you can set a specific option to do so (more information about this). All that you have to do is adding the following to the same file edited before: /etc/apt/apt.conf.d/50unattended-upgrades
And we’re done ! Hopefully your ubuntu system now upgrades php and all its extensions with last available patch version.
Bonus: Remove an old php major version from your system
When using only one php version, it feels safe to remove all others unused php versions. When unused it becomes useless to keep updating them, and more importantly it avoids some hard to catch mistakes ; eg: keep your webserver configuration pointing to an unwanted old php :/
sudo apt-get purge 'php7.3*'