Managing Multiple Local Sites with XAMPP and Virtual Hosts
If you develop multiple PHP projects locally on your Mac, sooner or later you end up with an htdocs folder that looks like a flea market…
Managing Multiple Local Sites with XAMPP and Virtual Hosts

If you develop multiple PHP projects locally on your Mac, sooner or later you end up with an htdocs folder that looks like a flea market: htdocs_project1, htdocs_project2, htdocs_old_client, htdocs_final_test_2, and so on. Or, even worse, you find yourself browsing to http://localhost/subfolder/anothersubfolder/ hoping that all the relative image paths do not break.
There is a clean, professional solution already built into XAMPP: Apache Virtual Hosts.
What is a Virtual Host?
A Virtual Host is an Apache configuration that allows a single web server to respond to multiple domain names, each pointing to a different folder on disk. In production, this technique has always been used to host multiple sites on the same physical server. Locally, we can use it in exactly the same way, assigning names like site1.test or site2.test to our projects, regardless of where they are located in the filesystem.
The end result is that you open your browser, type http://site1.test/, and see your site exactly as you would on a real domain, without nesting subfolders and creating confusion.
Why XAMPP and not Docker?
Before getting into the technical configuration, it is worth answering a question I hear often: “Wouldn’t it be better to use Docker?”
The answer is: it depends on the context. For teams working on enterprise projects with perfectly replicated production environments, Docker is the right choice. But for solo developers or small teams working on PHP projects with a traditional stack (Apache, MySQL, PHP), XAMPP has several practical advantages that Docker struggles to match in terms of operational simplicity.
XAMPP starts with one click. There are no daemons to manage, no Unix sockets to configure, no docker-compose.yml files to write or update every time you add a service. Open the control panel, press "Start" on Apache and MySQL, done.
XAMPP does not consume resources in the background. Docker Desktop on macOS runs a Linux virtual machine in the background, via Apple’s hypervisor framework, even when you are not doing anything. On machines with 8 or 16 GB of RAM, this overhead is noticeable. When XAMPP is stopped, it does nothing.
XAMPP does not require Docker knowledge to use it. This is not a criticism of Docker, which is a powerful and well designed tool. It is simply the observation that learning to manage containers, volumes, bridge networks, mapped ports, custom images, and compose files is a significant time investment. If you are building a PHP site for a local client, that investment is not justified.
XAMPP comes with phpMyAdmin ready to go. A small but practical detail: open http://localhost/phpmyadmin/ and manage your databases. With Docker, you also need to configure that.
In short, XAMPP is the right tool when you want to develop, not when you want to orchestrate infrastructure. Simplicity is not a limitation, it is a deliberate design choice.
Configuring Virtual Hosts on XAMPP for macOS
Let’s go through the complete procedure step by step.
Step 1: Enable the Virtual Host module in Apache
Apache in XAMPP already has everything needed, but virtual host configuration is disabled by default. We need to enable it.
Open Finder and navigate to:
/Applications/XAMPP/xamppfiles/etc/
Open the file httpd.conf with your preferred editor (VS Code works great). Find this section:
Virtual hosts
Include etc/extra/httpd-vhosts.conf
Remove the hash symbol before Include to uncomment the line:
Virtual hosts
Include etc/extra/httpd-vhosts.conf
Save and close the file.
Step 2: Define the Virtual Hosts
Now go to:
/Applications/XAMPP/xamppfiles/etc/extra/
Open the file httpd-vhosts.conf. You will find some example content: you can comment it out with # or delete it, then add your configuration at the bottom.
Here is a complete example that handles localhost, site1.test, and site2.test:
# Keep localhost working for the XAMPP dashboard and phpMyAdmin <VirtualHost :80> DocumentRoot “/Applications/XAMPP/xamppfiles/htdocs” ServerName localhost </VirtualHost>*
*# — — — — — — — — — — — — — — — — — — — — — — — —
PROJECT Site 1
— — — — — — — — — — — — — — — — — — — — — — — —
<VirtualHost :80> DocumentRoot “/Applications/XAMPP/xamppfiles/htdocs/htdocs_site1” ServerName site1.test
<Directory “/Applications/XAMPP/xamppfiles/htdocs/htdocs_site1”> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
*# — — — — — — — — — — — — — — — — — — — — — — — —
PROJECT Site2
— — — — — — — — — — — — — — — — — — — — — — — —
<VirtualHost :80> DocumentRoot “/Applications/XAMPP/xamppfiles/htdocs/htdocs_site2” ServerName site2.test
<Directory “/Applications/XAMPP/xamppfiles/htdocs/htdocs_site2”> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
Some useful notes:
DocumentRootpoints to the project root folder. It can be anywhere on your Mac, not necessarily insidehtdocs.AllowOverride Allis essential if you use.htaccessfiles for URL rewriting (for example in Laravel, WordPress, or any framework with pretty URLs).- The
.testextension is preferable to.local(which can conflict with mDNS on macOS) and.dev(which Chrome treats as HTTPS only).
Security note:
Require all grantedis appropriate for a local development environment, where the machine is not exposed to the public network. In production, access policies should be stricter, limiting access by IP, requiring authentication, or restricting directory options depending on the context.
Step 3: Register domains in the hosts file
Browsers do not know your local domains until you register them in the system hosts file, which works as a local DNS with absolute priority.
Open Terminal and edit the file with a command line editor:
sudo nano /etc/hosts
Add these lines at the bottom:
127.0.0.1 site1.test 127.0.0.1 site2.test
Save with Ctrl+O, then press Enter, then exit with Ctrl+X.
Step 4: Restart Apache
From the XAMPP control panel, press Stop and then Start on Apache, or use the Restart button. The new configuration will be loaded.

Step 5: Final check
Open your browser and navigate to:
http://site1.test/to see your first projecthttp://site2.test/to see the secondhttp://localhost/phpmyadmin/which will continue to work as usual
Each project responds to its own domain, has its own independent DocumentRoot, and the .htaccess file works correctly thanks to AllowOverride All.
Adding new projects in the future
Every time you start a new project, the procedure comes down to three steps:
- Add a new
<VirtualHost>block inhttpd-vhosts.conf. - Add the corresponding line in
/etc/hosts. - Restart Apache.
No new folders inside htdocs, no convoluted subpaths, no configuration conflicts between projects.
A note on MAMP, ServBay and others
It is worth mentioning the most common alternatives, especially on macOS.
MAMP (Macintosh, Apache, MySQL, PHP) is probably the best known alternative to XAMPP on Mac. It exists in a free version and a paid Pro version. The important point is that the free version of MAMP requires exactly the same manual procedure described in this article: same Apache configuration files, same /etc/hosts, same restart. There is no shortcut compared to XAMPP. MAMP Pro, on the other hand, offers a graphical interface for managing virtual hosts: you add a site, set the DocumentRoot, and MAMP Pro automatically writes the configuration files and updates /etc/hosts without opening an editor. It is a real convenience, but it is paid.
XAMPP remains cross platform: it works on macOS, Windows, and Linux with the same file structure and configuration logic. The equivalent on Linux is LAMPP (Linux, Apache, MySQL, PHP, Perl). For those working across multiple operating systems or wanting a consistent environment regardless of the machine, this portability is a real advantage. Even on MAMP, both free and Pro, the manual virtual host configuration procedure is identical to the one shown above, with slightly different paths (/Applications/MAMP/conf/apache/ instead of /Applications/XAMPP/xamppfiles/etc/).
**ServBay** is a much more recent and ambitious alternative, designed specifically to overcome the limitations of XAMPP and MAMP. It has a modern graphical interface, manages virtual hosts with one click, includes a built in local DNS server (which solves the /etc/hosts issue automatically), generates trusted local SSL certificates, and supports not only PHP but also Node.js, Python, Go, Ruby, and other runtimes in the same installation. The free version is already very generous for personal use and individual development, with a paid premium plan for advanced features. If you are starting from scratch and have no prior preferences, ServBay is probably the most complete local development environment available today on macOS.
But for a developer comfortable with the command line, editing two text files is really the bare minimum. The configuration shown above is learned once and then repeated mechanically. If even that feels like too much, it can be automated with a shell script to keep handy and use when needed:
*#!/bin/bash
Usage: ./new-vhost.sh <domain.test> <path/to/project>
Example: ./new-vhost.sh mysite.test /Applications/XAMPP/xamppfiles/htdocs/htdocs_mysite*
NAME=$1 PATH_ROOT=$2 VHOSTS=”/Applications/XAMPP/xamppfiles/etc/extra/httpd-vhosts.conf” HOSTS=”/etc/hosts”
if [ -z “$NAME” ] || [ -z “$PATH_ROOT” ]; then echo “Usage: $0 <domain.test> <path/to/project>” exit 1 fi
# Append the new VirtualHost block to httpd-vhosts.conf cat >> “$VHOSTS” <<EOF
<VirtualHost :80> DocumentRoot “$PATH_ROOT” ServerName $NAME <Directory “$PATH_ROOT”> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost> EOF*
# Add the entry to /etc/hosts echo “127.0.0.1 $NAME” | sudo tee -a “$HOSTS” > /dev/null
echo “Virtual host ‘$NAME’ created. Restart Apache from the XAMPP control panel.”
Save it as new-vhost.sh, make it executable with chmod +x new-vhost.sh, and from that point on adding a new local site becomes a single command in the terminal.
Note for macOS 26 users: mDNSResponder and hosts file bug
Readers might wonder whether it is worth avoiding manual editing of /etc/hosts altogether, using dnsmasq combined with the /etc/resolver/ mechanism instead. In theory, it is convenient: you create a /etc/resolver/test file that points to dnsmasq listening on 127.0.0.1, and from that point on any .test domain is resolved automatically without touching hosts each time.
On macOS 25 and earlier, this worked perfectly. On macOS 26, it does not.
A recent bug introduced in macOS 26 causes mDNSResponder to silently intercept DNS queries for any TLD not present in the IANA root zone, including .test, .internal, .lan, and any private TLD, treating them as mDNS without ever consulting the unicast nameserver specified in the resolver file. The result is that browsers, curl, ping, and any application using getaddrinfo() fail with "Unknown host", while scutil --dns shows the configuration as correct, leading users to believe everything is fine.
The particularly ironic point is that .test is reserved by RFC 6761 specifically for this purpose, local DNS testing, and the same RFC specifies that resolvers should handle it via normal DNS. macOS 26 treats it as an mDNS domain silently.
The documented workaround is exactly the method described in this article: modify /etc/hosts directly. This file is read before any DNS query and completely bypasses mDNSResponder. Paradoxically, the manual approach that might seem primitive is also the most robust and immune to operating system regressions.
The bug has been reported on Apple Feedback Assistant. If Apple fixes it, dnsmasq with /etc/resolver/ will become a valid alternative again for those who want automatic wildcards. Until then, it is better to stick with /etc/hosts.
Conclusion
Apache Virtual Hosts are a mature, stable feature already included in XAMPP without installing anything extra. Configuring them takes about twenty minutes the first time and a few minutes for each subsequent project. In return, you get a local development environment where each site has its own clean domain, exactly like in production, with all the benefits in terms of path readability, compatibility with modern frameworks, and mental clarity.
For developers working on PHP projects alone or in small teams, XAMPP with Virtual Hosts remains one of the most efficient local development environments available: lightweight, immediate, and completely out of the way when not needed.
Originally published at *Levysoft.*
메타데이터
- post_id
- b37a8a89dd0a
- slug
- managing-multiple-local-sites-with-xampp-and-virtual-hosts-b37a8a89dd0a
- url
- https://medium.com/@levysoft/managing-multiple-local-sites-with-xampp-and-virtual-hosts-b37a8a89dd0a
- canonical_url
- https://medium.com/@levysoft/managing-multiple-local-sites-with-xampp-and-virtual-hosts-b37a8a89dd0a
- author_url
- https://medium.com/@levysoft
- status
- ok
- fetched_at
- 2026-06-22 17:31:34