Classified ads board: Docker deployment and a drop from 15 seconds to 5
We deployed a commercial Laravel script in an isolated Docker stack, localised it into Russian, rebranded it and worked out why the page took fifteen seconds to open.
Three problems in one project
A purchased classified ads script had to be brought up locally without fighting the other stacks on the same machine (the database, Redis and admin ports were already taken), speak Russian, and open in a reasonable time. At the start the home page was loading in 13 to 15 seconds.
The database was not to blame
The first suspicion fell on the database queries. We measured: 75 to 88 queries add up to roughly 0.1 seconds, and not one of them is slow. The database is clean and the network has nothing to do with it. So the time is going before the code even starts running.
The real cause lies in the slow file mount from Windows into the container. With default settings PHP checks the modification date of every project file on every request. On a normal file system that goes unnoticed; across the Docker-for-Windows bridge it turns into thousands of slow calls per visit. It was made worse by the compiled file cache limit sitting at 10,000 against 21,359 PHP files in the project: the cache overflowed and recompiled the same things over and over.
What was done
An isolated Docker stack
Its own project name, network, volumes and ports. The stack does not conflict with the ones already running on the machine. It ships with PHP-FPM, Nginx, MariaDB, Redis and a mail catcher, so that letters do not escape from a test environment.
Installation from the console rather than the wizard
The browser install wizard kept tripping over CSRF, sessions and outbound calls. We went through it deterministically with console commands: migrations, filling the reference tables, the country and 2,658 cities, the super admin, the installation marker file. Repeatable and without surprises.
Russian by default
The language is switched in the database, in the config and for the admin. Browser auto-detection is switched off separately, otherwise an English header from the browser would override the Russian default. There is a trap here too: the default language is cached, and without clearing the cache the change is not visible.
Rebranding of exactly the visible part
We replaced what the user sees: the name, the footer, the service pages. The script's functional identifier was deliberately left alone: the code compares versions by it, and renaming it would break that logic. Checked: no mentions of the original brand are left on public pages.
Cache and sessions in Redis
Switching over exposed a trap: the session config defaulted to the database and brought the application down with a 500. It is fixed by naming the connection explicitly, one of those things that costs half an hour if you know and half a day if you do not.
What came out of it
We also recorded the route to going below one second: moving the code into a Linux file system instead of mounting it from Windows. That removes the root cause rather than the symptom, but it requires rebuilding the working environment, so the decision was left to the client as a deliberate choice.