This updated guide explains how to implement a scalable, production-ready setup where each user gets a Docker container and unique subdomain like user123.wizbrand.com, without creating new Apache VirtualHosts for each.
โ 1. Apache Configuration (Dynamic Reverse Proxy)
Apache Modules (Enable Once)
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod rewrite
sudo systemctl restart apache2
Apache Wildcard VirtualHost (Single File)
Edit /opt/lampp/etc/extra/httpd-vhosts.conf or /etc/apache2/sites-available/000-default.conf:
<VirtualHost *:80>
ServerName wizbrand.com
ServerAlias *.wizbrand.com
ProxyPreserveHost On
RewriteEngine On
# Extract user ID from subdomain (e.g., 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)
Restart Apache:
sudo systemctl restart apache2
โ 2. Laravel Controller to Spawn Container and Return URL
Create ContainerController.php:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ContainerController extends Controller
{
public function createUserContainer(Request $request)
{
$user = Auth::user();
$containerName = 'user-' . $user->id;
$port = 9000 + $user->id;
// Start Docker container mapped to unique port
shell_exec("docker run -d -p {$port}:80 --name {$containerName} my-image");
// Return container's unique URL
return response()->json([
'url' => "http://user{$user->id}.wizbrand.com"
]);
}
}
Code language: PHP (php)
Add Laravel Route (routes/web.php)
Route::get('/create-container', [ContainerController::class, 'createUserContainer'])->middleware('auth');
Code language: PHP (php)
โ 3. Domain Setup (Production)
In your domain provider’s DNS (e.g., GoDaddy, Cloudflare), add:
| Type | Name | Value |
|---|---|---|
| A | * | your_server_ip |
This wildcard allows user123.wizbrand.com โ your server.
โ 4. Local Testing Setup
Add to /etc/hosts (on dev machine)
127.0.0.1 user123.wizbrand.com
127.0.0.1 user456.wizbrand.com
Code language: CSS (css)
Or use:
nip.io:user123.127.0.0.1.nip.iosslip.io:user123.127.0.0.1.sslip.io
โ 5. Docker Image Assumptions
- Exposes port
80 - Named
my-imageor configured dynamically
Example container:
docker run -d -p 9123:80 --name user-123 my-image
Code language: CSS (css)
โ 6. Test Script (Optional Bash)
#!/bin/bash
USER_ID=$1
PORT=$((9000 + USER_ID))
CONTAINER="user-${USER_ID}"
# Launch container
sudo docker run -d -p ${PORT}:80 --name ${CONTAINER} my-image
# Access URL
echo "Container for user ${USER_ID} available at: http://user${USER_ID}.wizbrand.com"
Code language: PHP (php)
Usage:
./create-container.sh 123
๐ง Summary
| Component | Role |
|---|---|
| Apache (Wildcard) | Dynamic proxy via subdomain-to-port |
| Laravel | Container creator & subdomain router |
| Docker | User-specific environments |
| DNS (Wildcard) | Resolves all subdomains to one IP |
This approach is clean, scalable, reload-free, and requires just one Apache config regardless of user count. Let me know if you’d like to add Let’s Encrypt SSL automation, container auto-cleanup, or database tracking next.
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