A powerful CLI tool for managing virtual hosts with ease. Supports Nginx, Apache, and Caddy web servers. Create, configure, and manage virtual hosts for static sites, PHP applications, Laravel, WordPress, and reverse proxies with a single command.
- Multi-Server Support: Works with Nginx, Apache, and Caddy web servers
- Multiple Template Types: Support for static sites, PHP, Laravel, WordPress, and reverse proxy configurations
- SSL/TLS Support: Automatic Let's Encrypt certificate management via Certbot
- Easy Management: Add, remove, enable, disable, and list virtual hosts with simple commands
- Safe Operations: Built-in configuration testing and automatic rollback on failure
- Flexible Output: Human-readable colored output or JSON for scripting
- Cross-Platform: Builds for Linux and macOS (amd64/arm64)
- Web Server: Nginx, Apache, or Caddy installed and running
- Root/sudo access for modifying web server configurations
- Go 1.23+ (for building from source)
- PHP-FPM (optional, for PHP/Laravel/WordPress sites)
- Certbot (optional, for SSL certificate management)
# Clone the repository
git clone https://github.com/ksyq12/vhost.git
cd vhost
# Build
make build
# Install to /usr/local/bin (requires sudo)
make installDownload the appropriate binary for your platform from the Releases page.
# Linux (amd64)
curl -LO https://github.com/ksyq12/vhost/releases/latest/download/vhost-linux-amd64
chmod +x vhost-linux-amd64
sudo mv vhost-linux-amd64 /usr/local/bin/vhost
# macOS (Apple Silicon)
curl -LO https://github.com/ksyq12/vhost/releases/latest/download/vhost-darwin-arm64
chmod +x vhost-darwin-arm64
sudo mv vhost-darwin-arm64 /usr/local/bin/vhost# Add a static website
sudo vhost add example.com --type static --root /var/www/example
# Add a PHP application
sudo vhost add myapp.com --type php --root /var/www/myapp --php 8.2
# Add a Laravel project
sudo vhost add laravel.test --type laravel --root /var/www/laravel --php 8.2
# Add a WordPress site
sudo vhost add blog.com --type wordpress --root /var/www/wordpress --php 8.2
# Add a reverse proxy (e.g., for Node.js)
sudo vhost add api.example.com --type proxy --proxy http://localhost:3000
# Enable SSL
sudo vhost ssl install example.com --email admin@example.com
# List all virtual hosts
vhost list| Flag | Description |
|---|---|
--json |
Output in JSON format |
Add a new virtual host.
vhost add <domain> [flags]Flags:
| Flag | Short | Description |
|---|---|---|
--type |
-t |
VHost type: static, php, proxy, laravel, wordpress (default: static) |
--root |
-r |
Document root path (required for static, php, laravel, wordpress) |
--proxy |
-p |
Proxy pass URL (required for proxy type) |
--php |
PHP version (e.g., 8.2) |
|
--ssl |
Enable SSL (requires certbot) | |
--no-reload |
Don't reload Nginx after changes |
Examples:
# Static site
sudo vhost add example.com --type static --root /var/www/html
# PHP site with specific version
sudo vhost add app.com --type php --root /var/www/app --php 8.2
# Laravel with SSL
sudo vhost add laravel.test --type laravel --root /var/www/laravel --php 8.3 --ssl
# Reverse proxy for a Node.js app
sudo vhost add api.test --type proxy --proxy http://localhost:3000Remove a virtual host.
Aliases: rm, delete
vhost remove <domain> [flags]Flags:
| Flag | Short | Description |
|---|---|---|
--force |
-f |
Skip confirmation prompt |
--no-reload |
Don't reload Nginx after changes |
Examples:
# Remove with confirmation
sudo vhost remove example.com
# Force remove without confirmation
sudo vhost rm example.com --forceEnable a disabled virtual host.
vhost enable <domain> [flags]Flags:
| Flag | Description |
|---|---|
--no-reload |
Don't reload Nginx after changes |
Disable a virtual host (keeps configuration).
vhost disable <domain> [flags]Flags:
| Flag | Description |
|---|---|
--no-reload |
Don't reload Nginx after changes |
List all virtual hosts.
Aliases: ls
vhost list [flags]Flags:
| Flag | Description |
|---|---|
--json |
Output in JSON format |
Example Output:
DOMAIN TYPE ROOT/PROXY SSL ENABLED
example.com static /var/www/html no yes
api.example.com proxy http://localhost:3000 yes yes
laravel.test laravel /var/www/laravel no no
Install an SSL certificate using Let's Encrypt.
vhost ssl install <domain> --email <email>Flags:
| Flag | Short | Description |
|---|---|---|
--email |
-e |
Email for Let's Encrypt notifications (required) |
Example:
sudo vhost ssl install example.com --email admin@example.comRenew SSL certificate(s).
vhost ssl renew [domain] [flags]Flags:
| Flag | Description |
|---|---|
--all |
Renew all certificates |
Examples:
# Renew specific domain
sudo vhost ssl renew example.com
# Renew all certificates
sudo vhost ssl renew --allShow SSL certificate status for all domains.
vhost ssl statusShow detailed information about a virtual host.
vhost show <domain> [flags]Flags:
| Flag | Description |
|---|---|
--json |
Output in JSON format |
Example Output:
Domain: example.com
Type: laravel
Root: /var/www/laravel
PHP: 8.2
SSL: enabled
Cert: /etc/letsencrypt/live/example.com/fullchain.pem
Key: /etc/letsencrypt/live/example.com/privkey.pem
Expires: 2026-05-01
Enabled: yes
Created: 2026-02-01 10:00:00
Open the virtual host configuration file in an editor.
vhost edit <domain>Uses the $EDITOR environment variable (defaults to vi).
Examples:
# Open with default editor
vhost edit example.com
# Open with specific editor
EDITOR=nano vhost edit example.comNote: After editing, test and reload your web server manually:
# Nginx
sudo nginx -t && sudo systemctl reload nginx
# Apache
sudo apache2ctl configtest && sudo systemctl reload apache2
# Caddy
sudo caddy validate && sudo systemctl reload caddyView access and error logs for a virtual host.
vhost logs <domain> [flags]Flags:
| Flag | Short | Description |
|---|---|---|
--access |
Show access log only | |
--error |
Show error log only | |
--follow |
-f |
Follow log output (like tail -f) |
--lines |
-n |
Number of lines to show (default: 20) |
Examples:
# Show both logs (last 20 lines)
vhost logs example.com
# Show only access log
vhost logs example.com --access
# Show only error log
vhost logs example.com --error
# Follow logs in real-time
vhost logs example.com -f
# Show last 50 lines
vhost logs example.com -n 50Run diagnostic checks on the system and vhost configuration.
vhost doctor [flags]Flags:
| Flag | Description |
|---|---|
--json |
Output in JSON format |
Checks:
- Web server installation (Nginx, Apache, Caddy)
- PHP-FPM status (versions 8.3, 8.2, 8.1, 8.0, 7.4)
- Certbot installation
- Configuration file validity
- Virtual host status (enabled status, root directory, SSL certificates)
Example Output:
Checking system requirements...
✓ Nginx installed (1.25.3)
✓ PHP-FPM 8.2 running
✓ Certbot installed
Checking configuration...
✓ Config file exists (~/.config/vhost/config.yaml)
✓ Nginx config syntax OK
Checking vhosts...
✓ example.com - enabled, config valid
⚠ test.com - root directory missing
For serving static HTML, CSS, and JavaScript files.
- Serves
index.htmlandindex.htm - Security headers included
- Supports SSL with automatic HTTP to HTTPS redirect
sudo vhost add example.com --type static --root /var/www/htmlFor general PHP applications.
- PHP-FPM socket connection
- Configurable PHP version
.htaccessfile access blocked- URL rewriting support
sudo vhost add app.com --type php --root /var/www/app --php 8.2Optimized for Laravel framework.
- Automatic
publicdirectory routing - Laravel-style URL rewriting
.well-knowndirectory allowed (for SSL verification)- Hidden files blocked (except
.well-known)
sudo vhost add laravel.test --type laravel --root /var/www/laravel --php 8.2Optimized for WordPress CMS.
- WordPress permalink support
- Static file caching (js, css, images)
- Security hardening:
wp-config.phpaccess blockedxmlrpc.phpaccess blocked
- 64MB upload limit
- Optimized FastCGI buffers
sudo vhost add blog.com --type wordpress --root /var/www/wordpress --php 8.2For reverse proxying to backend applications.
- WebSocket support
- Proper header forwarding (X-Real-IP, X-Forwarded-For, X-Forwarded-Proto)
- Long timeout for persistent connections (24 hours)
sudo vhost add api.test --type proxy --proxy http://localhost:3000vhost uses Certbot for Let's Encrypt SSL certificate management.
# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx
# CentOS/RHEL
sudo dnf install certbot python3-certbot-nginx
# macOS (Homebrew)
brew install certbot- Certificate:
/etc/letsencrypt/live/<domain>/fullchain.pem - Private Key:
/etc/letsencrypt/live/<domain>/privkey.pem
Set up a cron job or systemd timer to automatically renew certificates:
# Add to crontab (runs twice daily)
0 0,12 * * * /usr/bin/certbot renew --quietvhost stores its configuration in ~/.config/vhost/config.yaml.
vhost supports multiple web server drivers. Set the driver in your configuration file:
# For Nginx (default)
driver: nginx
# For Apache
driver: apache
# For Caddy
driver: caddydriver: nginx # or "apache" or "caddy"
default_php: "8.2"
vhosts:
example.com:
domain: example.com
type: static
root: /var/www/html
ssl: false
enabled: true
created_at: 2026-02-01T10:00:00Z
api.example.com:
domain: api.example.com
type: proxy
proxy_pass: http://localhost:3000
ssl: true
ssl_cert: /etc/letsencrypt/live/api.example.com/fullchain.pem
ssl_key: /etc/letsencrypt/live/api.example.com/privkey.pem
enabled: true
created_at: 2026-02-01T11:00:00Z- Available sites:
/etc/nginx/sites-available/ - Enabled sites:
/etc/nginx/sites-enabled/(symlinks) - Access logs:
/var/log/nginx/<domain>-access.log - Error logs:
/var/log/nginx/<domain>-error.log
- Available sites:
/etc/apache2/sites-available/ - Enabled sites:
/etc/apache2/sites-enabled/(symlinks) - Access logs:
${APACHE_LOG_DIR}/<domain>-access.log - Error logs:
${APACHE_LOG_DIR}/<domain>-error.log
- Available sites:
/etc/caddy/sites-available/ - Enabled sites:
/etc/caddy/sites-enabled/(symlinks) - Access logs:
/var/log/caddy/<domain>-access.log - Note: Caddy provides automatic HTTPS by default via Let's Encrypt
# Build for current platform
make build
# Build for all platforms (Linux/macOS, amd64/arm64)
make build-all# Run all tests
make test
# Run tests with coverage
make test-coverage| Package | Coverage |
|---|---|
internal/executor |
100% |
internal/output |
100% |
internal/ssl |
95.1% |
internal/input |
87.5% |
internal/config |
81% |
internal/template |
79.2% |
internal/driver |
76.4% |
internal/cli |
15% |
# Format code
make fmt
# Run linter (requires golangci-lint)
make lint
# Tidy dependencies
make tidyvhost/
├── cmd/
│ └── vhost/
│ └── main.go # Entry point
├── internal/
│ ├── cli/ # CLI commands (Cobra)
│ │ ├── root.go # Root command
│ │ ├── add.go # Add command
│ │ ├── remove.go # Remove command
│ │ ├── enable.go # Enable command
│ │ ├── disable.go # Disable command
│ │ ├── list.go # List command
│ │ ├── ssl.go # SSL commands
│ │ └── common.go # Common utilities
│ ├── config/ # Configuration management
│ │ ├── config.go # Config struct and methods
│ │ └── vhost.go # VHost struct
│ ├── driver/ # Web server drivers
│ │ ├── driver.go # Driver interface
│ │ ├── nginx.go # Nginx implementation
│ │ ├── apache.go # Apache implementation
│ │ └── caddy.go # Caddy implementation
│ ├── executor/ # Command execution abstraction
│ │ └── executor.go # CommandExecutor interface & implementations
│ ├── input/ # User input handling
│ │ └── reader.go # Reader interface & implementations
│ ├── template/ # Config templates
│ │ ├── template.go # Template rendering
│ │ ├── embedded.go # Embedded templates
│ │ ├── nginx/ # Nginx templates
│ │ │ ├── static.tmpl
│ │ │ ├── php.tmpl
│ │ │ ├── proxy.tmpl
│ │ │ ├── laravel.tmpl
│ │ │ └── wordpress.tmpl
│ │ ├── apache/ # Apache templates
│ │ │ ├── static.tmpl
│ │ │ ├── php.tmpl
│ │ │ ├── proxy.tmpl
│ │ │ ├── laravel.tmpl
│ │ │ └── wordpress.tmpl
│ │ └── caddy/ # Caddy templates
│ │ ├── static.tmpl
│ │ ├── php.tmpl
│ │ ├── proxy.tmpl
│ │ ├── laravel.tmpl
│ │ └── wordpress.tmpl
│ ├── ssl/ # SSL certificate management
│ │ └── certbot.go # Certbot wrapper
│ └── output/ # Output formatting
│ └── formatter.go # Colored/JSON output
├── test/
│ └── integration/ # Integration tests
│ └── docker-compose.yml
├── Makefile
├── go.mod
└── go.sum
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Go best practices and conventions
- Add tests for new features
- Update documentation as needed
- Run
make lintbefore submitting
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ for the web development community