PHP settings, versions and extensions
The PHP settings belong to each website: its own version, its own php.ini, and which extensions are loaded. None of it needs a shell on the server, and none of it changes any other website.
The version
Per website, not per server.
Open a website and set its PHP version. Several versions are installed side by side, so an old application can stay on the version it was written for while a new one runs on the current release. Each PHP website gets a pool, a Unix identity and a socket of its own, which is what makes that possible: the versions are not sharing a process.
Changing the version restarts that website's PHP. Requests being served at that moment finish; nothing else on the server is affected.
If the version an application needs is not in the list, the panel can install another one, and it asks you two things rather than one. Ubuntu carries a single PHP version per release, so every other version comes from a third-party archive, and adding that archive changes what the server will accept packages from for everything on it, not only for PHP. That is why it is a separate question with its own consent. The list is added to and never reordered, because the first version in it is what a new website gets when nobody chooses, and sorting it would quietly move every website made afterwards.
On Ubuntu 26.04 this is not available yet. The archive has no packages for 26.04, so there is nothing to install, and the panel says so rather than offering a command that cannot work. A server on 24.04 can add the versions a migrated application needs today.
The settings
A form, or the file itself.
Open a website and go to PHP settings. There are two editors over the same settings, because there are two ways people arrive at this page.
Simple is a form. The five most asked for are at the top, and they are the five below. Thirty-three more are grouped under uploads and input, errors, sessions, time and output, OPcache, performance and mail. Each one says what it does and what it costs, so notice changed files explains that turning it off is faster, and means a file you upload is not used until PHP restarts. Every control has a third position, PHP’s default, so you can put something back without knowing what the default was.
| Setting | What it decides | Range |
|---|---|---|
Memory for one requestmemory_limit |
The most memory one page may use before PHP stops it. An application that handles images or spreadsheets needs more than one that serves pages. | 32 to 1024 MB |
Largest uploadupload_max_filesize |
The largest single file somebody may upload to this website. | 1 to 512 MB |
Largest form submissionpost_max_size |
Everything one form may send, the files in it included. | 1 to 512 MB, and never smaller than the largest upload. Setting it lower is refused rather than silently capping your uploads. |
Time for one requestmax_execution_time |
How long one page may take before PHP stops it. An import or a report needs longer; a website that needs longer for an ordinary page has something else wrong. | 1 to 300 seconds |
Form fields per requestmax_input_vars |
How many fields one form may send. A settings page or a menu editor with hundreds of rows is what runs into this, and the symptom is a form that saves most of itself. | 100 to 10,000 fields |
One cross-check catches a pairing that would otherwise fail at the worst moment: a website’s memory limit has to be able to hold one request. If the website is capped at 256 MB under Limits, a PHP memory limit above that is refused, and the message says which to raise first. Either page can be the one that breaks the pair, so both make the check.
Advanced is the file. Write php.ini syntax, one setting a line, and keep your own comments. It is for working from an application’s documentation with a list of settings to apply:
# Nextcloud asks for these memory_limit = 512M upload_max_filesize = 512M post_max_size = 512M max_execution_time = 300 output_buffering = Off # and the timezone it nags about date.timezone = America/Halifax
The whole text may be 16 KB and name at most 400 settings. Both bounds exist because PHP-FPM reads this file at every restart, and because a paste of something that is not a php.ini should be refused rather than become one.
Both edit the same thing. A setting changed in the form appears in the text, and a line you typed in the text is not disturbed by a change made in the form.
Scheduled tasks and the one-click installers run under these same settings, so an installer that refuses on a limit sees the limit you set rather than the distribution’s default. A task that dies without printing much is often a task that ran out of memory: raise the limit for the website and read Task output again.
While you type
A wrong line is refused before it is saved.
PHP ignores a setting it does not have. So a misspelt name is the worst kind of mistake to make in a php.ini: it saves, it applies, and it does nothing, which looks exactly like the panel not working. Every line is checked as you type.
- A value outside its range is named with the range it has.
- A misspelt setting is refused with the name you meant:
max_input_vargets youmax_input_vars. - A timezone that does not exist is refused against the zone database, rather than leaving an application an hour out.
- The same setting twice is refused with the line it was first set on, instead of one of the two quietly winning.
- A setting the panel does not know, such as one an extension brings with it, is accepted and written exactly as typed, and the page says so rather than pretending to have checked it.
error_reportingcan be written the way the manual writes it.E_ALL & ~E_DEPRECATEDbecomes the number it means, because the file these settings go into is read by PHP-FPM, which does not know the names and reads the expression as nothing at all.
Underneath, the panel shows the lines it will actually write, so you can see the result rather than trust that it understood you.
What is not yours to set
Thirty-eight settings, each with where it does live.
Some settings are the server’s, and the page lists every one of them with the reason. open_basedir is what keeps this website out of another customer’s files. Sessions and uploads stay inside the website. error_log is what fills the log view, so pointing it elsewhere would empty a page you need. disable_functions belongs to the protection profile. An extension is chosen under PHP extensions, where the panel knows which ones this server has.
They are refused rather than accepted and then overridden. A setting that looks saved and does nothing costs an afternoon; a refusal that explains itself costs a moment.
The settings go into the website’s own PHP-FPM pool as admin values, which means the application cannot change them back from its own code. They never go into a .user.ini next to your files, because that is a second place the same setting would live, writable by whatever the website is running, and then nobody can say what a website’s PHP is actually doing.
One setting is a default rather than a rule. Showing errors in the page is off unless you ask for it. That is right for a live website, because an error message carries the full path of the file it happened in, and it is exactly what you want while you are building something. Recording them is not optional either way.
The extensions
Grouped by what you are trying to do.
PHP extensions are listed by purpose rather than as an alphabetical wall of package names, because the question is almost never "do I want imagick". It is "I need to resize images". Turn on what the application needs and the panel fetches the package and loads it.
Two things follow from how PHP extensions work. Enabling one fetches a package, so it takes a moment and needs the server to reach its package mirror. And PHP restarts to load them, the same brief restart as a version change, because an extension is loaded when the process starts and not while it is running.
An extension is enabled for the website that asked for it. It is not turned on globally, so one customer's requirement does not quietly become every website's attack surface.
There are a lot of them, so the list filters and the two buttons above it load or unload everything it is showing. Filter for what you are after and press Load these rather than finding each switch: with a filter typed, the buttons act on what the filter shows and reach nothing outside it.
What PHP may not do
It cannot run a command.
The runtime is built without the functions that start a program, so PHP cannot run a command on these servers. Applications that shell out to a binary will not work, and that is the intended trade: a website that is broken into is not then a way to run programs on the machine.
If an application genuinely needs a system utility, it belongs on the server rather than inside a hosted website. Most of the time the extension list is the real answer, because the thing being shelled out to has a PHP extension that does it in process.