Website being served on internal private IP but not on public IP

1. Caddy version (caddy version):


2. How I run Caddy:

I run Arch Linux on Scaleway VPS. It has a public and private IP.

When I run the following command I do not see the public IP:

$ sudo ip -4 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    altname enp0s2
    altname ens2
    inet <private IP>/31 metric 100 scope global dynamic eth0
       valid_lft 51079sec preferred_lft 51079sec

Apparently the default Caddyfile loads configs from config.d so I included two config files in that directory. One config is set to serve the website on private IP and another on public IP.

$ cat t0
<private IP> {
	tls internal
	respond "Hello World!"
$ cat t1
<public IP> {
	tls internal
	respond "Hello World!"

a. System environment:

Arch Linux, Using systemd

b. Command:

sudo systemctl start caddy

c. Service/unit/compose file:

Description=Caddy web server
Documentation= systemd-networkd-wait-online.service

ExecStartPre=/usr/bin/caddy validate --config /etc/caddy/Caddyfile
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
ExecStopPost=/usr/bin/rm -f /run/caddy/admin.socket

# Do not allow the process to be restarted in a tight loop. If the
# process fails to start, something critical needs to be fixed.

# Use graceful shutdown with a reasonable timeout


# Hardening options
ReadWritePaths=/var/lib/caddy /var/log/caddy /run/caddy


caddy fmt:

# The Caddyfile is an easy way to configure your Caddy web server.
# The configuration below serves a welcome page over HTTP on port 80.
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace the line below with your
# domain name.
	# Restrict the admin interface to a local unix file socket whose directory
	# is restricted to caddy:caddy. By default the TCP socket allows arbitrary
	# modification for any process and user that has access to the local
	# interface. If admin over TCP is turned on one should make sure
	# implications are well understood.
	admin "unix//run/caddy/admin.socket"

# Import additional caddy config files in /etc/caddy/conf.d/
import /etc/caddy/conf.d/*

3. The problem I’m having:

As I have mentioned earlier I have two config files: t0 config files serves the website on a private IP and t1 serves the website on the public IP.

The website is being served only on the private IP.

$ curl --insecure https://<private IP>
Hello World!
$ curl --insecure https://<public IP>
curl: (7) Failed to connect to <public IP> port 443 after 1 ms: No route to host

4. Error messages and/or full log output:

● caddy.service - Caddy web server
     Loaded: loaded (/etc/systemd/system/caddy.service; enabled; vendor preset: disabled)
     Active: active (running) since Wed 2022-02-16 20:30:19 UTC; 31min ago
    Process: 5416 ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile (code=exited, status=0/SUCCESS)
   Main PID: 5279 (caddy)
      Tasks: 7 (limit: 1141)
     Memory: 16.5M
        CPU: 783ms
     CGroup: /system.slice/caddy.service
             └─5279 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile

Feb 16 20:38:56 sirius caddy[5279]: {"level":"info","ts":1645043936.481402,"msg":"autosaved config (load with --resume flag)","file":"/var/lib/caddy/autosave.json"}
Feb 16 20:38:56 sirius caddy[5279]: {"level":"info","ts":1645043936.4816153,"logger":"admin.api","msg":"load complete"}
Feb 16 20:38:56 sirius caddy[5279]: {"level":"info","ts":1645043936.4845903,"logger":"admin","msg":"stopped previous server","address":"unix//run/caddy/admin.socket"}
Feb 16 20:38:56 sirius systemd[1]: Reloaded Caddy web server.
Feb 16 20:50:29 sirius systemd[1]: Reloading Caddy web server...
Feb 16 20:50:29 sirius caddy[5416]: {"level":"info","ts":1645044629.7391555,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":""}
Feb 16 20:50:29 sirius caddy[5279]: {"level":"info","ts":1645044629.744595,"logger":"admin.api","msg":"received request","method":"POST","host":"","uri":"/load","remote_addr":"@","headers":{"Accept-Encoding":["gzip"],"Content-Length":["562"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}}
Feb 16 20:50:29 sirius caddy[5279]: {"level":"info","ts":1645044629.7449164,"logger":"admin.api","msg":"config is unchanged"}
Feb 16 20:50:29 sirius caddy[5279]: {"level":"info","ts":1645044629.7449396,"logger":"admin.api","msg":"load complete"}
Feb 16 20:50:29 sirius systemd[1]: Reloaded Caddy web server.

5. What I already tried:

I am really new to caddy. I don’t know where to start. I have an inkling that the website is on public IP is not being served because the public IP is not present on any interface on the system… But ssh is working with no issue…

6. Links to relevant resources:

Hey @silverj0hn, welcome to the Caddy community.

This is a networking (routing, specifically) issue, not a Caddy issue.

With this setup, Caddy is listening for any request on any interface for hosts <private IP> and <public IP> and will respond appropriately. It just seems like your curl command can’t figure out how to reach that public IP address, which is beyond the scope of Caddy.

You can test that Caddy is “serving” your site on the public IP address by making a request to the private IP address but requesting the public IP address as the Host, i.e.:

curl -H "Host: <public IP>" --insecure https://<private IP>

You should see that Caddy receives the requests and responds in the appropriate manner for the “public” site.

This leads me into my next point: what specifically is your goal when separating your site in this manner? If the goal is security (i.e. the private site is ONLY served on the private interface and the public site is ONLY served on the public interface), this configuration will not suffice, as Caddy will respond on any interface with any site by using the Host header to differentiate which site to serve. Instead you will want to look into bind (Caddyfile directive) — Caddy Documentation.

If the goal is not security but rather convenience, and it is not a security concern for people to access the “private” site over the public IP if they wanted to craft a specific request manually, then this should be fine as soon as you resolve the networking issue.


It just seems like your curl command can’t figure out how to reach that public IP address, which is beyond the scope of Caddy.

True. It is a reconfiguration issue with the Arch Linux image on scaleway VPS. Other OS images do not have this issue; at least Debain.

what specifically is your goal when separating your site in this manner? If the goal is security

I only bothered with a “private IP” only because the public IP seems unreachable but bind seems interesting; can images some interesting use cases such as admin panel being only accessible from a private network.

Thank you.

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.