Tech 3 min read

[Docker] Recreating Shared Hosting Development Environments in 2025 - Sakura and Lolipop Edition

IkesanContents

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

ItemVersion
Docker29.0.1
Docker Compose2.40.3

Overview

Service Container HTTP HTTPS Base OS
Sakura environmentsakurahttp://localhost:8081https://localhost:8443AlmaLinux 9
Lolipop environmentlolipophttp://localhost:8082https://localhost:8444Ubuntu 24.04
MySQL 8.0rental-mysqllocalhost:3306--
phpMyAdminrental-phpmyadminhttp://localhost:8080--
Mailpitrental-mailpithttp://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
  • .htaccess enabled
  • 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 Secure attribute only work over HTTPS
  • APIs such as navigator.geolocation also 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:

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:

ItemValue
Hostlocalhost
Port3306
Userdevuser
Passworddevpass

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 itemWhat I changed
php-jsonRemoved, because PHP 8.x includes it by default
msmtp-mtaRemoved, because AlmaLinux does not provide that package
ssl.conf / php.confRemoved because they conflicted with the default configuration
Listen 443Added because removing ssl.conf also removes it
/run/php-fpmCreated 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.