[Docker] Recreating Shared Hosting Development Environments in 2025 - Sakura and Lolipop Edition
Contents
Background
Most of my client work is not the kind of project with budgets like AWS or Google Cloud. It is usually Sakura Internet, and sometimes Lolipop.
When you develop PHP for shared hosting projects, you run into problems like these:
- You can only test in production
- “It worked locally” problems
- Endless loops of upload via FTP, then test, then repeat
To solve that, I recreated Sakura Internet and Lolipop environments in Docker.
Verified Setup
| Item | Version |
|---|---|
| Docker | 29.0.1 |
| Docker Compose | 2.40.3 |
Overview
| Service | Container | HTTP | HTTPS | Base OS |
|---|---|---|---|---|
| Sakura environment | sakura | http://localhost:8081 | https://localhost:8443 | AlmaLinux 9 |
| Lolipop environment | lolipop | http://localhost:8082 | https://localhost:8444 | Ubuntu 24.04 |
| MySQL 8.0 | rental-mysql | localhost:3306 | - | - |
| phpMyAdmin | rental-phpmyadmin | http://localhost:8080 | - | - |
| Mailpit | rental-mailpit | http://localhost:8025 | - | - |
The full code lives in the GitHub repository: https://github.com/hide3tu/sakura-lolipop-docker
Design Principles
What to include
- Apache 2.4
- PHP 8.3 + standard extensions (mbstring, gd, curl, intl, pdo_mysql, zip, and so on)
- mod_rewrite
.htaccessenabled- SSL with a self-signed certificate
What not to include
- Composer
- Node.js / npm
- Other build tools
Reason: If you write code that depends on Composer or npm, it will not run in production. That is how you end up with “it worked locally” problems. It is safer to write with the real environment constraints in mind.
Unified Path Layout
Both environments use the same directory layout:
/home/user/www/ <- document root
/home/user/log/ <- log output
/home/user/tmp/ <- temporary files
That way, you can develop without constantly thinking about environment differences.
Key Details
php-fpm Integration
To reproduce shared-hosting CGI/FastCGI behavior, I used php-fpm instead of mod_php.
# /etc/httpd/conf.d/php-fpm.conf
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
On AlmaLinux, the default php.conf uses a Unix socket, so remove it.
msmtp + Mailpit
Emails sent with PHP’s mail() function are caught by Mailpit. Nothing is actually sent outside, so accidental sends during development are avoided.
# /etc/msmtprc
account default
host mailpit
port 1025
from noreply@localhost
auth off
tls off
On the PHP side, point sendmail_path at msmtp:
sendmail_path = /usr/bin/msmtp -t
php.ini Per Directory
Just like Sakura Internet, placing a php.ini in each directory lets you override settings.
# Add to /etc/php.ini
user_ini.filename = php.ini
user_ini.cache_ttl = 300
Example:
projects/sakura/www/
├── index.php
├── php.ini <- applied to the whole root
└── admin/
├── index.php
└── php.ini <- applied under admin/
Self-Signed SSL Certificate
Why HTTPS is needed:
- Mixed content problems (HTTP APIs are blocked from HTTPS pages)
- Cookies with the
Secureattribute only work over HTTPS - APIs such as
navigator.geolocationalso require HTTPS
Generate a self-signed certificate valid for 10 years:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/httpd/ssl/server.key \
-out /etc/httpd/ssl/server.crt \
-subj "/C=JP/ST=Tokyo/L=Tokyo/O=LocalDev/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
Usage
Setup
# Clone
git clone https://github.com/hide3tu/sakura-lolipop-docker.git
cd sakura-lolipop-docker
# Create project directories
mkdir -p projects/sakura/{www,log}
mkdir -p projects/lolipop/{www,log}
# Build and start
docker-compose up -d --build
Verification
# Create test files
echo '<?php phpinfo();' > projects/sakura/www/index.php
echo '<?php phpinfo();' > projects/lolipop/www/index.php
Check in the browser:
- Sakura: http://localhost:8081
- Lolipop: http://localhost:8082
Database Connection
From PHP:
<?php
$pdo = new PDO(
'mysql:host=mysql;port=3306;dbname=development;charset=utf8mb4',
'devuser',
'devpass'
);
From external tools such as TablePlus:
| Item | Value |
|---|---|
| Host | localhost |
| Port | 3306 |
| User | devuser |
| Password | devpass |
Email Test
<?php
mail('test@example.com', 'Test subject', 'Test body');
The sent email can be checked at http://localhost:8025.
Notes
- The real Sakura production environment uses FreeBSD, but Docker is Linux-based, so I used AlmaLinux as a substitute
- Apache and PHP behavior are compatible, but OS-specific behavior can still differ
- I recommend testing in the real environment before production deployment
Summary
| Fixed item | What I changed |
|---|---|
php-json | Removed, because PHP 8.x includes it by default |
msmtp-mta | Removed, because AlmaLinux does not provide that package |
ssl.conf / php.conf | Removed because they conflicted with the default configuration |
Listen 443 | Added because removing ssl.conf also removes it |
/run/php-fpm | Created because php-fpm will not start unless the directory exists |
If the build fails, check the items above.
One side note: I have recently seen people on X saying that Docker Desktop is unnecessary.
This article only uses docker-compose, and there is no GUI management involved.
Personally, though, I like being able to visually understand what an image and a container are. That may not sound very developer-like, but I feel more comfortable when I can check things in a GUI instead of doing everything through the terminal.