The SOAP entry script is now index_soap.php
Read this page if an installation answers SOAP requests: settings/soap.ini [GeneralSettings] EnableSOAP=true, the
syndication extension exporting content to other installations, or a middleware product that calls functions an
extension registered. If SOAP is off (the default), nothing changes for you; the rules on this page are still the
ones to use the day you switch it on.
Warning
.htaccess slows down every request. When .htaccess files are enabled (AllowOverride anything but None), let alone
used, Apache looks for them and reads and evaluates them on every request, in every directory of the path, and
page loading times go up drastically (measured). The only real fix is to switch the feature off for
the virtual host: AllowOverride None in the HTTPS virtual host, and the rules in the virtual host's own
configuration as mod_rewrite rules. That is far faster in production speed tests and well worth the time it takes
to optimize a production configuration. Switch over right away: copy the rules of the
example HTTPS virtual host into your virtual host (with the static cache, also
staticcache_offload.conf), set AllowOverride None, run apachectl configtest, reload Apache and
test the site. The same rules for other servers: nginx, LiteSpeed,
Caddy, IIS, Velocity (built in); where virtual host rules go in a control
panel: Plesk, cPanel, DirectAdmin, ISPConfig.
On LiteSpeed or OpenLiteSpeed, the server's own page cache can also answer anonymous visitors and crawlers without PHP: Page caching with LiteSpeed and OpenLiteSpeed.
Changed on 29 October 2026, in the 6.0.15 line.
Contents
- What changed
- Why
- What keeps working for now
- What you must change
- Apache: .htaccess and the HTTPS virtual host
- Plesk
- nginx
- Other servers and Exponential Velocity
- The SOAP clients
- Test it
- For developers
What changed
| Before (6.0.14 and older) | Now (6.0.15) |
|---|---|
soap.php in the root of the installation was the SOAP server | index_soap.php is the SOAP server |
soap.php is a shim: it writes a notice at most once a day and includes index_soap.php, nothing else | |
https://www.example.com/soap.php | https://www.example.com/index_soap.php |
The server itself did not change: the same settings (soap.ini), the same extensions
([ExtensionSettings] SOAPExtensions[], extension/<name>/soap/initialize.php), the same sign-in with HTTP basic
credentials, the same answers. Only its file name changed.
A second sign-in step (two-factor authentication) still never applies to SOAP: an account that needs one signs in over SOAP with an app password, as before. See the second step on the other sign-in paths.
Why
- One name pattern for every front controller. The scripts the web server may run are
index.php,index_rest.php,index_treemenu.phpandindex_cluster.php.soap.phpwas the odd one out, so every set of rewrite rules, every nginxlocation, every list of allowed scripts needed a special case for it, and many installations that switched SOAP on simply forgot it: their SOAP requests ended atindex.php, which answered with a page or a 404. - Hardened rules stay simple. The shipped rules run no
.phpfile because its path was asked for, except the front controllers in the root. With the SOAP server named like them, a rule such as^index(_[a-z]+)?\.php$describes all of them, and a scanner or an audit can tell a front controller from a stray script by its name. - The WebDAV server follows the same pattern in the same release (
webdav.phpbecomesindex_webdav.php); see the WebDAV entry script is now index_webdav.php.
What keeps working for now
soap.phpstill answers. It only includesindex_soap.php, so a client or a rule that still names it gets the same answer as before. The URIs and the siteaccess are read relative to the name the request used.Once a day a request through
soap.phpwrites one notice tovar/log/warning.log:[ Oct 29 2026 09:12:03 ] [192.0.2.10] soap.php: A request came through soap.php, the deprecated name of the SOAP entry script. It still answers, but change the web server rules and the SOAP clients to index_soap.php (Exponential 6.0.15). Requested URI: /soap.phpThe day is kept as the modification time of
var/log/soap-php-deprecated.stamp; delete that file to get the notice again on the next request. Ifvar/log/does not exist or cannot be written, the shim writes nothing and still answers.The shim will be removed in a later major version. Do not build anything new on
soap.php.
What you must change
- Update the code to 6.0.15 (or later) as usual.
index_soap.phpand the shim arrive together. - Let
index_soap.phpthrough in the web server, in every place that letssoap.phpthrough today: the.htaccessof the installation, the HTTPS virtual host (*:443) and, where both exist, the plain HTTP one (*:80), Plesk's additional directives, the nginx server block. The sections below give the lines. - Point every SOAP client at
index_soap.php: the import settings of thesyndicationextension on every importing installation, middleware, scripts, monitoring checks. See the SOAP clients. - Reload the web server and test both the new address and, until every client has moved, the old one.
- Watch
var/log/warning.log(and the web server's access log) forsoap.php. When nothing has called it for a while, you may refuse it at the web server (RewriteRule ^soap\.php$ - [F,L], nginxlocation = /soap.php { return 403; }) so a forgotten client fails loudly instead of using a name that will disappear.
Where the web server lets every existing file through (a RewriteCond %{REQUEST_FILENAME} !-f before the rule that
sends everything to index.php), index_soap.php is reached without a rule of its own. Test it all the same.
Apache: .htaccess and the HTTPS virtual host
The shipped .htaccess_root (copied to .htaccess) and .htaccess_root_static carry the line, commented out,
right after the REST API's rules. Uncomment it when SOAP is on:
RewriteRule ^api/ index_rest.php [L]
RewriteRule ^index_rest\.php - [L]
# The SOAP server (settings/soap.ini EnableSOAP=true) is index_soap.php since
# Exponential 6.0.15; soap.php, its old name, only forwards to it. Uncomment
# when SOAP is switched on, and let the SOAP clients call index_soap.php:
RewriteRule ^index_soap\.php - [L]If your .htaccess has a line for the old name, such as RewriteRule ^soap\.php - [L], change it to the line above
(and keep the old one only while clients still call soap.php).
In a virtual host the rules are in server context, so the patterns start with /. In the <VirtualHost *:443> block
(and in <VirtualHost *:80> if SOAP is also served over plain HTTP, which it should not be):
<VirtualHost *:443>
# ...
RewriteEngine On
RewriteRule ^/api/ /index_rest.php [L]
RewriteRule ^/index_rest\.php - [L]
RewriteRule ^/index_soap\.php - [L]
# while old clients still call soap.php:
RewriteRule ^/soap\.php - [L]
# ...
RewriteRule . /index.php [L]
</VirtualHost>A virtual host that hands PHP to PHP-FPM only for a list of scripts (<FilesMatch "^(index|index_rest|index_treemenu)\.php$">
with SetHandler "proxy:unix:...|fcgi://localhost") needs index_soap in that list too, or Apache sends the source
of index_soap.php as a file:
<FilesMatch "^(index|index_rest|index_treemenu|index_soap)\.php$">
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</FilesMatch>A restriction to the addresses of the importing installations, which the syndication page recommends, moves with the name:
<Location "/index_soap.php">
Require ip 192.0.2.10 198.51.100.0/24
</Location>Check the configuration and reload: apachectl configtest && systemctl reload httpd (apache2 on Debian).
Plesk
Plesk keeps the rules of a domain in Websites & Domains > (domain) > Apache & nginx Settings > Additional
directives for HTTPS (and for HTTP). It writes them into the domain's vhost_ssl.conf (vhost.conf for HTTP)
below /var/www/vhosts/system/<domain>/conf/; edit them in the panel, or in those files followed by
plesk repair web <domain> -y, not in the generated httpd.conf.
- In Additional directives for HTTPS, wherever
soap.phpappears (aRewriteRule, a<Location>, a<Files>or<FilesMatch>that names the scripts for PHP-FPM), add or change the same line forindex_soap.php, as in the virtual host above. - With nginx proxy mode on, also add the nginx part in Additional nginx directives if it names
soap.php(see nginx); with proxy mode the requests reach Apache unless nginx answers them itself. - Plesk's PHP handler for the domain (PHP-FPM served by Apache, or by nginx) runs every
.phpfile the rules let through; nothing to change there.
nginx
nginx has no .htaccess. A server block in the style of the shipped example
(nginx, doc/eng-us/examples/web-servers/nginx.conf) lists each front
controller in its own location; the example carries the SOAP one commented out. With SOAP on:
location = /index_soap.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_soap.php;
fastcgi_param SCRIPT_NAME /index_soap.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}Change an existing location = /soap.php (or a location ~ ^/(index|index_rest|soap)\.php$) the same way: the
location, SCRIPT_FILENAME and SCRIPT_NAME all name index_soap.php. A SCRIPT_FILENAME that still points at
soap.php keeps working through the shim, but writes the daily notice. Keep a location = /soap.php with the same
three lines (all naming soap.php) only while old clients still call it, then answer it with return 403;.
An allow/deny list for the importing installations goes into the index_soap.php location.
Check and reload: nginx -t && systemctl reload nginx.
Other servers and Exponential Velocity
- LiteSpeed and OpenLiteSpeed read the Apache rules: add
RewriteRule ^/?index_soap\.php - [L]next to theindex_rest.phprule (the OpenLiteSpeed example has it, commented out). - Caddy and FrankenPHP: add
/index_soap.phpto the paths the@frontmatcher leaves alone (@front not path /index_rest.php /index_treemenu.php /index_soap.php). - IIS: a rule that matches
^index_soap\.phpwith the action None, next toexp-rest-direct. - Exponential Velocity runs only
index.php,index_rest.phpandindex_treemenu.php(the server'swebserver.scripts); it never ransoap.phpeither. Serve SOAP through the Apache or nginx front end of the installation, which hands it to PHP-FPM, and keep the SOAP clients on that address.
The SOAP clients
Every system that calls the SOAP server names its address; change it from .../soap.php to .../index_soap.php:
- The
syndicationextension, on every installation that imports: Syndication > Imports > (import) > Edit, the field for the server address, for examplehttps://export.example.com/index_soap.php. Fromsyndication1.3.14 on, the wizard givesindex_soap.phpas the example, and the dashboard and a feed's page of the exporting installation showindex_soap.phpwhen its kernel has it (soap.phpon an older one). An exporting installation that still runs 6.0.14 or older is called atsoap.php. - Middleware and scripts: the endpoint address in their configuration.
- Monitoring: a check that posts to the SOAP server.
Until all of them have moved, soap.php keeps answering; the daily notice tells you that something still calls it.
Test it
Run these from a machine that is allowed to reach the SOAP server, against the HTTPS name of the site. Replace
www.example.com with that name.
A GET answers, not 404. The Exponential SOAP server has no WSDL; a GET (with
?wsdlor without) gets a short message, which proves that the request reached the SOAP server and notindex.php:curl -sS -i 'https://www.example.com/index_soap.php?wsdl'Expect
HTTP/1.1 200(orHTTP/2 200) and the bodyError: this web page does only understand POST methods. WithEnableSOAP=falsethe answer is200with an empty body. A404, the site's front page or its "page not found" HTML means the rewrite rule is missing and the request went toindex.php. The PHP source in the body means the script was not handed to PHP (see theFilesMatchabove).A POST of a minimal SOAP envelope answers with a SOAP fault, here for a function that does not exist, so it changes nothing:
curl -sS -i -X POST 'https://www.example.com/index_soap.php' \ -H 'Content-Type: text/xml; charset=utf-8' -H 'SOAPAction: ""' \ --data-binary '<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><exp:ping xmlns:exp="http://example.com/exp"/></SOAP-ENV:Body></SOAP-ENV:Envelope>'Expect
200,Content-Type: text/xmland a body with<SOAP-ENV:Fault>andMethod not found. That is the right answer: the server parsed the envelope and looked the function up. With credentials (-u login:password) of an account that needs a second sign-in step and no app password, the answer is401withWWW-Authenticate: Basic realm="Exponential SOAP"and a fault that names the reason.The old name still answers while you need it: repeat 1 and 2 with
soap.php. The answers are the same, andvar/log/warning.loggets onesoap.php:notice for the day.Nothing calls the old name any more. After the clients have moved:
grep -c 'soap\.php' /var/log/httpd/ssl_access_log # Apache; nginx: /var/log/nginx/access.log grep -A1 'soap\.php:$' var/log/warning.log | tail -4On Plesk the access log of a domain is
/var/www/vhosts/system/<domain>/logs/access_ssl_log. Requests for/soap.phpafter the change are clients you have not moved yet; the line also shows their address. The requests for/index_soap.phpare the ones that moved.A real call. On an importing installation, open the import of the
syndicationextension and fetch the list of exported content (or run the import's cronjob): it should list the feeds of the exporting side as before.
For developers
index_soap.phpis the script;soap.phpholds no logic. Changeindex_soap.php.eZSys::init()gets the name of the script the request named (index_soap.php, orsoap.phpthrough the shim), so the URIs and the siteaccess match are read relative to it.expUserSessionTracker::detectMethod()counts a sign-in through either name assoap.- Tests:
tests/tests/kernel/classes/expSoapEntryScriptTest.php(no database) runs the shim in a PHP process of its own beside a stand-inindex_soap.php: it forwards, writes one notice a day, and still answers withoutvar/log/.