Jump to content

Caddy: Difference between revisions

→‎Reverse proxy: Add example on forward real client ip
imported>Malteneuss
(Simplify installation example)
(→‎Reverse proxy: Add example on forward real client ip)
 
(16 intermediate revisions by 7 users not shown)
Line 2: Line 2:
It can also be a reverse proxy to serve multiple web services under one server. Its main features are its simple config setup and automatic HTTPS: It will automatically request and renew a LetsEncrypt certificate so that users of your service get a Browser-trusted and secure connection.
It can also be a reverse proxy to serve multiple web services under one server. Its main features are its simple config setup and automatic HTTPS: It will automatically request and renew a LetsEncrypt certificate so that users of your service get a Browser-trusted and secure connection.


== Installation ==
== Get started ==


To try out Caddy add the following minimal example to your NixOS module:
To try out Caddy add the following minimal example to your [[NixOS modules | NixOS module]]:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
services.caddy = {
{
  enable = true;
  # ...
  virtualHosts."localhost:80".extraConfig = ''
  services.caddy = {
    respond "Hello, world!"
    enable = true;
  '';
    virtualHosts."localhost".extraConfig = ''
};   
      respond "Hello, world!"
    '';
  };
}  
</syntaxhighlight>
 
This snippet will let Caddy respond on <code>http://localhost</code> and <code>https://localhost</code> with a dummy text "Hello world!". When no port is mentioned on virtualhost like just <code>localhost</code> instead of <code>localhost:8080</code>, Caddy listens on <code>80</code> and <code>443</code> by default and redirects requests from port 80 (unsecured) to 443 (secured).
 
==== Check http connection ====
 
You can use <code>curl</code> to test the http connections:
 
<syntaxhighlight lang="bash">
$ curl localhost -i -L -k
HTTP/1.1 308 Permanent Redirect
Location: https://localhost/
..
 
HTTP/2 200
alt-svc: h3=":443"; ma=2592000
content-type: text/plain; charset=utf-8
...
 
Hello, world!
</syntaxhighlight>
 
Here you can see that Caddy automatically redirects from an unsecure http://localhost to a secure https://localhost call.
For local addresses like "localhost" Caddy always generates and uses a self-signed certificate, which curl correctly doesn't trust; use the <code>-k</code> flag to ignore that.
 
==== Check http(s) connection ====
 
When virtualhost and "real" host aren't the same it gets complicated with HTTPS, so the following curl command works:
 
<syntaxhighlight lang="bash">
$ curl --connect-to <virtualhost>:443:<realhost>:443 https://<virtualhost> -k
Hello, world!
</syntaxhighlight>
</syntaxhighlight>


The snippet above will run Caddy on http://localhost and respond with a dummy text "Hello world!".
Curl will set <code>Host</code> header and TLS <code>SNI</code> in the request to <code><virtualhost></code> as desired by Caddy, but will make the actual request against the <code><realhost></code>, e.g. a load-balancer or ingress-controller.


A similar example with serving a dummy "http://localhost/example.html" page is:
Alternatively with http and automatic redirects to https you can extend that call:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="bash">
services.caddy = {
$ curl --connect-to <virtualhost>:80:<realhost>:80 --connect-to <virtualhost>:443:<realhost>:443 https://<virtualhost> -k -L
  enable = true;
Hello, world!
  virtualHosts."localhost".extraConfig = ''
    encode gzip
    file_server
    root * ${
      pkgs.runCommand "testdir" {} ''
        mkdir "$out"
        echo hello world > "$out/example.html"
      ''
    }
  '';
}; 
</syntaxhighlight>
</syntaxhighlight>


== Configuration examples ==
* [https://curl.se/docs/manpage.html#--connect-to curl connect-to documentation]
* [https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header Curl on HTTPS, SNI, Host]
* [https://github.com/caddyserver/caddy/issues/2656#issuecomment-1627342466 curl to Caddy over HTTPS]
 
== Typical configurations ==


=== SSL ===
=== SSL ===
Line 54: Line 82:
     }
     }
   '';
   '';
};
};  
networking.firewall.allowedTCPPorts = [ 80 443];
</syntaxhighlight>
</syntaxhighlight>


Line 66: Line 95:
   virtualHosts."example.org".extraConfig = ''
   virtualHosts."example.org".extraConfig = ''
     reverse_proxy http://10.25.40.6
     reverse_proxy http://10.25.40.6
  '';
  virtualHosts."another.example.org".extraConfig = ''
    reverse_proxy unix//run/gunicorn.sock
   '';
   '';
};
};
</syntaxhighlight>
</syntaxhighlight>In case you would like to forward the real client IP of the request to the backend, add following headers<syntaxhighlight lang="nix">
 
services.caddy = {
* [https://caddyserver.com/docs/quick-starts/reverse-proxy Caddy reverse proxy documentation]
  virtualHosts."example.org".extraConfig = ''
    reverse_proxy http://10.25.40.6 {
      header_down X-Real-IP {http.request.remote}
      header_down X-Forwarded-For {http.request.remote}
    }
  '';
};
</syntaxhighlight>Fur further reverse proxy configuration, see [https://caddyserver.com/docs/quick-starts/reverse-proxy upstream documentation].


=== Redirect ===
=== Redirect ===
Line 81: Line 120:
   virtualHosts."example.org" = {
   virtualHosts."example.org" = {
     extraConfig = ''
     extraConfig = ''
       redir https://www.example.org
       redir https://www.example.org{uri}
   '';
   '';
     serverAlias = [ "old.example.org" ];
     serverAliases = [ "old.example.org" ];
};
};
</syntaxhighlight>
</syntaxhighlight>
Line 110: Line 149:
=== Check used ports ===
=== Check used ports ===


To check if Caddy is running and listening as configured you can run netstat:
To check if Caddy is running and listening as configured you can run <code>netstat</code>:
 
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
$ netstat -tulpn
$ netstat -tulpn
Line 121: Line 161:
</syntaxhighlight>
</syntaxhighlight>
The tcp (ipv4) socket port 2019 is Caddy's management endpoint, for when you want manage its config via web REST calls instead of Nix (ignore).
The tcp (ipv4) socket port 2019 is Caddy's management endpoint, for when you want manage its config via web REST calls instead of Nix (ignore).
The tcp6 (an ipv6 socket that also listens on ipv4) socket on port 80 (HTTP) and 443 (HTTPS) indicate that a virtualhost config was used.
The tcp6 (an ipv6 socket that also listens on ipv4) socket on port 80 (HTTP) and 443 (HTTPS) indicate that our virtualhost config was used.


=== Check connections ===
=== Virtualhost and real host not identical ===
 
You can also use curl to test http(s) calls. However, you must set the "Host" header correctly when testing locally:
<syntaxhighlight lang="bash">
$ curl localhost -H "Host: example.org"
</syntaxhighlight>


for an virtualhost config like  
When you connect to Caddy must ensure that the "Host" header matches the virtualhost entry of Caddy. For example, when testing locally a config like  


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
Line 140: Line 175:
};
};
</syntaxhighlight>
</syntaxhighlight>
you must send the request against "localhost" and manually override the host header to "example.org":
<syntaxhighlight lang="bash">
$ curl localhost -i -H "Host: example.org"
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://example.org/
Server: Caddy
...
</syntaxhighlight>
Above you also see the redirect from http://localhost to https://example.org; Caddy always redirects from the unsecure to the secure port of your virtualhost.


If the response is empty, try setting a port number like 80 and/or try a local TLS security certificate instead of global LetsEncrypt:
If the response is empty, try setting a port number like 80 and/or try a local TLS security certificate instead of global LetsEncrypt:
Line 165: Line 213:


[[Category:Applications]]
[[Category:Applications]]
[[Category:Web Servers]]
[[Category:Server]]
[[Category:Networking]]
63

edits