2026年11月12日
2026年11月12日
Apache Listen on Multiple IPs: ports.conf and IP-Based Virtual Hosts
This article is a localized edition of the Japanese original. Read the Japanese original
By default Apache has Listen 80, which accepts connections on port 80 on every IP address of the server. If you want to separate internal and external traffic by IP address, or serve a different site on each IP address, you specify IP addresses in Listen.
This article shows how to make Apache 2.4 listen on several specific IP addresses. Paths follow Ubuntu 24.04 / Debian 12 as of October 2026, with differences for RHEL-family systems (AlmaLinux, Rocky Linux) noted along the way. The example addresses 192.0.2.10 and 198.51.100.20 are for documentation only; replace them with your own.
Prerequisite: the IP addresses must be assigned to the server
Apache can only listen on IP addresses that are actually assigned to the server's network interfaces. Check this first.
ip -brief address
If you put an address that isn't assigned in Listen, Apache fails to start and the error log shows Cannot assign requested address. Add IP addresses with netplan on Ubuntu or NetworkManager (nmcli) on RHEL-family systems. On a cloud server, you also need to assign the secondary IP in the provider's console.
Listen syntax
The syntax is Listen [IP-address:]portnumber [protocol]. Even when you specify an IP address, the port number cannot be omitted.
# Specify an IP address and a port
Listen 192.0.2.10:80
Listen 198.51.100.20:80
# Enclose IPv6 addresses in []
Listen [2001:db8::10]:80
If you write Listen 192.0.2.10 without a port, loading the configuration fails with the error Port must be specified and Apache does not start.
Edit the configuration file
Where Listen lives depends on the OS.
| OS | File |
|---|---|
| Ubuntu / Debian | /etc/apache2/ports.conf |
| RHEL family | /etc/httpd/conf/httpd.conf |
On Ubuntu, ports.conf initially contains the following:
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
The key point is not to add Listen 192.0.2.10:80 while keeping the existing Listen 80. Listen 80 means port 80 on every IP address, so it overlaps with the line for the specific IP. The official Apache manual says overlapping Listen directives are a fatal error that prevents the server from starting (the error log shows something like Address already in use: ... could not bind to address 192.0.2.10:80).
To restrict listening to specific IP addresses, rewrite Listen 80:
# /etc/apache2/ports.conf
Listen 192.0.2.10:80
Listen 198.51.100.20:80
<IfModule ssl_module>
Listen 192.0.2.10:443
Listen 198.51.100.20:443
</IfModule>
<IfModule mod_gnutls.c>
Listen 192.0.2.10:443
Listen 198.51.100.20:443
</IfModule>
If you want to keep listening on all IP addresses and only serve a different site per IP address, leave Listen 80 alone; the virtual host settings below are enough. Restrict Listen to specific IPs only when there are addresses you don't want to listen on at all (for example, so the admin site is not served on the public IP).
Serve a different site per IP address (virtual hosts)
Listen only decides which addresses and ports to listen on, not which site to return. To serve a different site per IP address, put the IP address and port in <VirtualHost>.
# /etc/apache2/sites-available/internal.conf
<VirtualHost 192.0.2.10:80>
ServerName intranet.example.com
DocumentRoot /var/www/internal
ErrorLog ${APACHE_LOG_DIR}/internal_error.log
CustomLog ${APACHE_LOG_DIR}/internal_access.log combined
</VirtualHost>
# /etc/apache2/sites-available/public.conf
<VirtualHost 198.51.100.20:80>
ServerName www.example.com
DocumentRoot /var/www/public
ErrorLog ${APACHE_LOG_DIR}/public_error.log
CustomLog ${APACHE_LOG_DIR}/public_access.log combined
</VirtualHost>
On Ubuntu, enable the new configuration with a2ensite. If you restricted Listen to specific IPs, you can keep the default 000-default.conf (<VirtualHost *:80>), but disable it if you don't need it.
sudo a2ensite internal.conf public.conf
# Disable the default site if you don't need it
sudo a2dissite 000-default.conf
On RHEL-family systems, any .conf file in /etc/httpd/conf.d/ is loaded. Change ErrorLog to something like /var/log/httpd/... (${APACHE_LOG_DIR} is a Debian-family variable).
If Apache isn't listening on the address and port given in <VirtualHost>, that site can't be reached. Make sure Listen and <VirtualHost> match.
HTTPS sites
HTTPS works the same way: put SSLEngine on and the certificate settings inside <VirtualHost 192.0.2.10:443>. On port 443 the Listen protocol is https automatically. Only when serving HTTPS on another port do you add the protocol, as in Listen 192.0.2.10:8443 https.
Apply and verify
# Syntax check
sudo apache2ctl configtest
# Apply (restart here, to recreate the listening sockets)
sudo systemctl restart apache2
On RHEL-family systems, use sudo apachectl configtest and sudo systemctl restart httpd.
Check which addresses Apache listens on and which virtual hosts they map to.
# Addresses and ports being listened on
sudo ss -ltnp | grep -E 'apache2|httpd'
# Which virtual host is assigned to which address
sudo apache2ctl -S
If the ss output lists 192.0.2.10:80 and 198.51.100.20:80 and there is no *:80 (0.0.0.0:80), listening is restricted to those IP addresses.
Send a request to each IP address and confirm that you get different sites.
curl -sI http://192.0.2.10/
curl -sI http://198.51.100.20/
Troubleshooting
| Error log message (excerpt) | Cause | Fix |
|---|---|---|
(98)Address already in use: ... could not bind to address |
Listen 80 overlaps with an IP-specific Listen, or another program such as nginx is using the same port |
Check ports.conf and find the program using the port with sudo ss -ltnp |
(99)Cannot assign requested address: ... could not bind to address |
The IP address isn't assigned to the server | Check with ip -brief address and assign the IP address |
no listening sockets available, shutting down |
None of the listeners could be opened | Check whether either of the two messages above appears |
The error log is /var/log/apache2/error.log on Ubuntu and /var/log/httpd/error_log on RHEL-family systems. Right after a failed start, you can also check sudo journalctl -u apache2 -n 50 (-u httpd on RHEL-family systems).
Connections also fail if ports 80 and 443 aren't open in the firewall (ufw or firewalld) or are blocked by a cloud security group. If Apache is listening but can't be reached from outside, check those.
Related articles
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)