The easiest way would be to use different public IP for each services (there can only be one sofware to listen on a specific port+IP combination).
But I assume you don’t have multiple IPv4. So, another solution is to put a reverse proxy on front of your current services. The reverse proxy will listen on port 80 and 443 on your public IPs (IPv4 and IPv6), and you will change Apache and Nginx so that they only listen on local IPv4 (for example 127.0.0.2 for Apache and 127.0.0.3 for Nginx).
This solution is not easy, is not perfect, and requires a really good comprehension of what you are doing. It has drawbacks.
For example, I am using HAProxy to achieve this (having an Apache server for some services and NGinx for others, on the same public IP).
Here is my HAProxy config file:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http-in
bind X.X.X.X:80 # replace X.X.X.X by your public IPV4
bind :::80 v6only # here I can listen on every IPv6, because Apache and NGinx will only listen on IPv4 addresses
mode http
acl acl_apache hdr(host) an_apache_website.mydomain.tld # replace by the url of one of your apache service. Add as many line as services using Apache.
acl acl_nginx hdr(host) an_nginx_website.mydomain.tld # same for your nginx services (peertube here)
use_backend backend_apache if acl_apache
use_backend backend_nginx if acl_nginx
frontend https-in
bind X.X.X.X:443 # Same as before, replace X.X.X.X by your public IPv4
bind :::443 v6only
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend backend_apache_ssl if { req_ssl_sni -i an_apache_website.mydomain.tld}
use_backend backend_nginx_ssl if { req_ssl_sni -i an_nginx_website.mydomain.tld }
backend backend_apache
mode http
option forwardfor except 127.0.0.1
server apache 127.0.0.2:80
backend backend_apache_ssl
mode tcp
option ssl-hello-chk
server apache 127.0.0.2:443 send-proxy-v2
backend backend_nginx
mode http
option forwardfor except 127.0.0.1
server nginx 127.0.0.3:80
backend backend_nginx_ssl
mode tcp
option ssl-hello-chk
server nginx 127.0.0.3:443 send-proxy-v2
Then, you will have to change Apache and Nginx configuration so that they only listen on:
- 127.0.0.2 port 80 and 443 for Apache (in /etc/apache2/ports.conf, replace
listen: *:80
by Listen 127.0.0.2:80
, and same for port 443)
- 127.0.0.3 port 80 and 443 for Nginx (in your peertube nginx config file, replace
#listen [::]:80;
by listen 127.0.0.3:80;
, and same for port 443)
You will also have to enable the ProxyProtocol on your apache virtualhosts. To achieve that, you have to add this in your virtualhosts:
RemoteIPProxyProtocol On
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1
If you don’t add this, Apache will see all incomming requests as coming from localhost. The HAPproxy configuration tells to add some header with the real IP of the end user. Adding this configuration to Apache tells Apache to read this X-Forwarded-For header, and using this IP as the original one.
For Nginx, you have to add this in your /etc/nginx/nginx.conf file, in the http{} section:
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
I think that’s all.
Again, this is not an easy solution, and you should not use it if you don’t understand what you are doing.
PS: it is just an example of how to achieve this. You can do more clever configurations depending on your setup and constraints.