This tutorial guides you through setting up a multi-user container-based architecture using:
- Laravel (running on Apache via XAMPP in Ubuntu VM)
- Docker (to spawn a container for each user)
- Apache (as a reverse proxy)
- Domain:
wizbrand.com
We’ll configure Apache to dynamically proxy subdomains like user123.wizbrand.com to each user’s container (e.g., port 9123).
๐ 1. Environment Setup
1.1. Prerequisites
- Ubuntu VM
- XAMPP (with Apache)
- Docker installed
- Laravel app running in XAMPP (
htdocs/myapp)
๐ง 2. Laravel: Container Creation Endpoint
Create a route and controller in Laravel to spawn a Docker container and generate a proxy URL.
Example Laravel Controller
public function createUserContainer()
{
$user = auth()->user();
$containerName = 'user-' . $user->id;
$port = 9000 + $user->id;
// Start Docker container with mapped port
shell_exec("docker run -d -p $port:80 --name $containerName my-image");
// Create Apache virtualhost config
$vhost = "
<VirtualHost *:80>
ServerName $containerName.wizbrand.com
ProxyPreserveHost On
ProxyPass / http://localhost:$port/
ProxyPassReverse / http://localhost:$port/
</VirtualHost>
";
file_put_contents("/opt/lampp/etc/extra/vhosts/$containerName.conf", $vhost);
// Append hosts file (for local dev only)
file_put_contents("/etc/hosts", "\n127.0.0.1 $containerName.wizbrand.com", FILE_APPEND);
// Reload Apache
shell_exec("sudo /opt/lampp/lampp reloadapache");
return response()->json(['url' => "http://$containerName.wizbrand.com"]);
}
Code language: PHP (php)
Replace
my-imagewith your actual Docker image name
๐ 3. Apache Configuration
3.1 Enable Apache Modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2 # or /opt/lampp/lampp restart
Code language: PHP (php)
3.2 Main Apache Config File
Ensure it includes:
# In httpd.conf or extra/httpd-vhosts.conf
IncludeOptional etc/extra/vhosts/*.conf
Code language: PHP (php)
Create folder:
sudo mkdir /opt/lampp/etc/extra/vhosts
๐ 4. Domain & Local Setup
4.1 Production DNS Setup
- Add one wildcard DNS record:
*.wizbrand.com โ your_server_ip
Code language: CSS (css)
4.2 Local Development Setup
- Edit
/etc/hostson host system (your laptop):
127.0.0.1 user-123.wizbrand.com
127.0.0.1 user-456.wizbrand.com
Code language: CSS (css)
๐ค 5. Laravel Route (routes/web.php)
Route::get('/create-container', [ContainerController::class, 'createUserContainer'])->middleware('auth');
Code language: PHP (php)
๐ 6. Workflow Summary
- User logs into Laravel app
- Clicks button to create container
- Laravel creates Docker container on a unique port
- Laravel generates Apache virtualhost config
- Apache proxies
userXYZ.wizbrand.comโ user’s container - User accesses the unique subdomain URL
๐ Optional Enhancements
- Use Laravel queue to create containers async
- Setup SSL (Letโs Encrypt + wildcard)
- Add container expiry/auto-deletion scheduler
- Store container info in DB
๐จ Caveats
- Apache config reload is needed for each new subdomain (downtime may be noticeable)
- Traefik/Nginx are more scalable but not used here as per your request
- Ensure ports are not reused across containers
๐ Tools Used
- Laravel (PHP Backend)
- Docker (User environment containers)
- Apache (Reverse proxy)
- XAMPP (AMP stack)
๐ Conclusion
This setup allows you to offer per-user container environments with unique URLs, using Apache as a reverse proxy without requiring manual DNS records for each user. It’s great for development, testing, or isolated workspaces.
You’re absolutely right โ the solution I gave does involve creating a new Apache VirtualHost config per container, which works but is not scalable for hundreds of users.
Since youโre looking for a better, scalable approach using Apache only (no Traefik or Nginx), here’s the optimized solution you’re likely aiming for:
โ Improved Approach: One Wildcard VirtualHost + Rewrite Rules
Instead of generating a new VirtualHost file for every container/user, weโll use one single wildcard-based VirtualHost that dynamically reverse-proxies based on the subdomain.
๐ง Concept
Assume:
- Each user gets a subdomain like
user123.wizbrand.com - Each container listens on a unique port like
91XXX(e.g., 9123 for user 123)
We’ll use mod_rewrite and mod_proxy to extract the subdomain and map it to the corresponding port dynamically.
๐ง Step-by-Step: Dynamic Apache Reverse Proxy Using Subdomains
โ 1. Enable Required Apache Modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod rewrite
sudo systemctl restart apache2
โ 2. Single Wildcard VirtualHost Configuration
Edit your Apache config (XAMPP: /opt/lampp/etc/extra/httpd-vhosts.conf or Ubuntu default: /etc/apache2/sites-available/000-default.conf):
<VirtualHost *:80>
ServerName wizbrand.com
ServerAlias *.wizbrand.com
ProxyPreserveHost On
RewriteEngine On
# Extract username from subdomain (user123)
RewriteCond %{HTTP_HOST} ^user([0-9]+)\.wizbrand\.com$ [NC]
RewriteRule ^/(.*)$ http://127.0.0.1:9%1/$1 [P,L]
ProxyPassReverse / http://127.0.0.1/
</VirtualHost>
Code language: PHP (php)
โ This does the magic:
- Matches
user123.wizbrand.com - Extracts
123from the subdomain - Proxies to
localhost:9123
โ 3. Docker Container Port Strategy
Each container should expose port 80 to a host port like 9123.
Example command from Laravel:
$containerName = "user-{$user->id}";
$hostPort = 9000 + $user->id;
shell_exec("docker run -d -p {$hostPort}:80 --name {$containerName} my-image");
Code language: PHP (php)
โ 4. DNS Setup (Production)
In your domain DNS provider (for wizbrand.com), create:
| Type | Name | Value |
|---|---|---|
| A | * | your_server_ip |
This allows
*.wizbrand.comto point to your server automatically.
โ
5. Local Development (/etc/hosts)
For testing on your local machine or VM:
127.0.0.1 user123.wizbrand.com
127.0.0.1 user456.wizbrand.com
Code language: CSS (css)
Or use dynamic wildcard resolution services like:
nip.io:user123.127.0.0.1.nip.iosslip.io:user123.127.0.0.1.sslip.io
๐ Summary: Why This is Better
| Feature | Previous Method | Improved Method โ |
|---|---|---|
| VHost per user | Yes โ | No โ |
| Apache reload for each user | Yes โ | No โ |
| Scalable for 100+ users | Not practical โ | Fully scalable โ |
| Performance-friendly | No โ | Yes โ |
| Maintains Apache-only setup | Yes โ | Yes โ |
๐ Laravel Integration Recap
$port = 9000 + $user->id;
shell_exec("docker run -d -p {$port}:80 --name user-{$user->id} my-image");
return response()->json([
'url' => "http://user{$user->id}.wizbrand.com"
]);
Code language: PHP (php)
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services โ all in one place.
Explore Hospitals