Jump to content

Caddy: Difference between revisions

946 bytes added ,  8 July 2023
Fix content error in introduction
imported>Malteneuss
m (Add example how to open NixOS ports)
imported>Malteneuss
(Fix content error in introduction)
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 module:
Line 9: Line 9:
services.caddy = {
services.caddy = {
   enable = true;
   enable = true;
   virtualHosts."localhost:80".extraConfig = ''
   virtualHosts."localhost".extraConfig = ''
     respond "Hello, world!"
     respond "Hello, world!"
   '';
   '';
Line 15: Line 15:
</syntaxhighlight>
</syntaxhighlight>


The snippet above will run Caddy on http://localhost and respond with a dummy text "Hello world!".
This snippet will let Caddy respond on http://localhost and https://localhost with a dummy text "Hello world!". When no port is mentioned on virtualhost like just "localhost" instead of "localhost:8080", Caddy listens on 80 and 443 by default and redirects requests on port 80 (unsecured) to 443 (secured).
 
==== Check used ports ====
 
To check if Caddy is running and listening as configured you can run netstat:
 
<syntaxhighlight lang="bash">
$ netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address          Foreign Address        State      PID/Program name   
tcp        0      0 127.0.0.1:2019          0.0.0.0:*              LISTEN      1202/caddy           
tcp6      0      0 :::80                  :::*                    LISTEN      1202/caddy         
tcp6      0      0 :::443                  :::*                    LISTEN      1202/caddy         
udp6      0      0 :::443                  :::*                                1202/caddy           
</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 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 connection ====
 
You can use curl to test the http(s) connections:


A similar example with serving a dummy "http://localhost/example.html" page is:
<syntaxhighlight lang="bash">
$ curl localhost -i -L -k
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://localhost/
Server: Caddy
date: Sat, 08 Jul 2023 11:56:05 GMT
Content-Length: 0


<syntaxhighlight lang="nix">
HTTP/2 200
services.caddy = {
alt-svc: h3=":443"; ma=2592000
  enable = true;
content-type: text/plain; charset=utf-8
  virtualHosts."localhost".extraConfig = ''
server: Caddy
    encode gzip
content-length: 15
    file_server
date: Sat, 08 Jul 2023 11:56:05 GMT
    root * ${
 
      pkgs.runCommand "testdir" {} ''
Hello, world!
        mkdir "$out"
        echo hello world > "$out/example.html"
      ''
    }
  '';
}; 
</syntaxhighlight>
</syntaxhighlight>


== Configuration examples ==
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 "-k" flag to ignore that.
 
== Typical configurations ==


=== SSL ===
=== SSL ===
Line 109: Line 133:
== Debugging ==
== Debugging ==


=== Check used ports ===
You can use curl to test http(s) calls. However, you must ensure that the "Host" header matches the virtualhost entry of Caddy. For example, when testing locally a config like  
 
To check if Caddy is running and listening as configured you can run netstat:
<syntaxhighlight lang="bash">
$ netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address          Foreign Address        State      PID/Program name   
tcp        0      0 127.0.0.1:2019          0.0.0.0:*              LISTEN      1202/caddy           
tcp6      0      0 :::80                  :::*                    LISTEN      1202/caddy         
tcp6      0      0 :::443                  :::*                    LISTEN      1202/caddy         
udp6      0      0 :::443                  :::*                                1202/caddy           
</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 tcp6 (an ipv6 socket that also listens on ipv4) socket on port 80 (HTTP) and 443 (HTTPS) indicate that a virtualhost config was used.
 
=== Check connections ===
 
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  


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
Line 141: Line 143:
};
};
</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:
Anonymous user