/ Readme.org
Readme.org
  1  #+title: Caddy for noob
  2  #+author: HaQadosch
  3  #+date: [2023-12-02 Sat]
  4  #+startup: indent
  5  #+property: header-args :results output
  6  #+link caddy https://caddyserver.com/
  7  #+link doc https://caddyserver.com/docs/getting-started
  8  * Org mode shortcuts
  9  - tangle :: ~org-babel-tangle~, ~C-c C-v C-t~
 10  
 11  ** Config
 12  - ~C-c C-c~ :: Refresh local setup for that file
 13  
 14  ** Dates:
 15  - ~C-c .~ :: active timestamps
 16    creates an entry in the agenda
 17  - ~C-c !~ :: inactive timestamps
 18    doesn´t create an entry in the agenda
 19  - link :: [[https://orgmode.org/orgguide.html#Timestamps][timestamps]]
 20  
 21  ** Links:
 22  - ~C-c C-l~ :: create link
 23  - link :: [[https://orgmode.org/orgguide.html#Hyperlinks][hyperlinks]]
 24  
 25  ** Tables
 26  - ~C-c }~ :: display cells references
 27  - ~C-c ?~ :: display ref for that cell
 28    references are =@ROW$COLUMN=
 29  - link :: [[https://orgmode.org/manual/References.html][table references]]
 30  - formula :: =@I..II=
 31    select all the rows between horizontal lines (hline) 1 and 2
 32    =vmean(@I..II);EN= column range mean, treats empty values as null (0)
 33  
 34  ** Whitespace
 35  - ~M-x whitespace-mode~ :: Activates a better whitespace mode
 36  - ~M-x auto-fill-mode~ :: Auto-fill, enforce max size limit
 37  - ~M-q~ :: Force auto-fill on current paragraph
 38  
 39  ** Feetnotes
 40  - ~C-c C-x f~ :: Creates a footnote, see [[https://orgmode.org/guide/Creating-Footnotes.html][guide]].
 41  - ~C-c C-c~ :: to jump between definition and refs.
 42  
 43  ** Todos
 44  - ~C-c C-t~ :: cycling throught the states of the todos
 45  - ~C-u C-c C-t~ :: Log the change of status
 46  
 47  ** Clocking work
 48  - ~C-c C-x C-i~ :: Clock in
 49  - ~C-c C-x C-o~ :: Clock out
 50  - ~C-c C-x C-d~ :: Display clocks
 51  
 52  ** Includes files
 53  Start with the directive ~INCLUDE~ and the location of the file
 54    - ~C-c '~ :: Visit the included file
 55    - ~C-c &~ :: Go back to the original doc
 56    🟡 The included doc start at the hierarchy of the inclusion
 57    See [[https://orgmode.org/manual/Include-Files.html][the manual]]
 58  
 59  ** Code Block - Structure Template
 60  - ~C-c C-,~ :: Insert structure template
 61  See [[https://orgmode.org/manual/Structure-Templates.html][17.2 Structure Templates]]
 62  and [[https://orgmode.org/manual/Structure-of-Code-Blocks.html][16.2 Structure of Code Blocks]]
 63  
 64  * Emacs Shortcut
 65  - Toggle display of quick help buffer :: ~C-h C-q~ or ~M-x cheat-sheet~
 66  
 67  * Start with initial config
 68  It can be either *JSON* or *Caddyfile*, knowing that the caddyfile will be
 69  adapted to *JSON*.
 70  #+begin_src caddyfile
 71    :2015
 72  
 73    respond "Hello, you!"
 74  #+end_src
 75  
 76  using the command
 77  #+begin_src shell
 78    caddy adapt                     # --config /path/to/Caddyfile
 79  #+end_src
 80  
 81  the caddyfile will be adapted to JSON
 82  #+begin_src json
 83    {
 84      "apps":{
 85        "http":{
 86          "servers":{
 87            "srv0":{
 88              "listen":[":2015"],
 89              "routes":[
 90                {"handle":[
 91                  {"body":"Hello, you!","handler":"static_response"}
 92                ]}
 93              ]
 94            }
 95          }
 96        }
 97      }
 98   }
 99  #+end_src
100  
101  If there is a a file called ~Caddyfile~ in the current directory and
102  no other config file specified, Caddy will load the Caddyfile config,
103  adapt it, and run it right away.
104  #+begin_src shell
105    caddy run
106  #+end_src
107  
108  There are several ways to start Caddy with an initial config:
109  - A file named Caddyfile in the current directory
110  - the ~--config~ flag
111    optionally with the ~--adapter~ flag if the name is not Caddyfile
112  - the ~--resume~ flag
113    if a config was loaded previously
114  
115  
116  * Background / Foreground
117  #+name: Foreground
118  #+description: This will block the current terminal
119  #+begin_src shell
120    caddy run
121    # Ctrl+c to stop the process
122  #+end_src
123  
124  #+name: Background
125  #+description: This will unblock the terminal
126  #+begin_src shell
127    caddy start
128    caddy stop                      # the Ctrl+c command won't work
129  #+end_src
130  
131  You could also use the ~/stop~ endpoint
132  #+begin_src shell
133    curl localhost:2015/stop
134  #+end_src
135  
136  * Config reload
137  Stopping, loading a new config, and starting the server will result to
138  downtime 🙅🏻
139  For a graceful config change, use ~caddy reload~.
140  
141  * API way of working
142  
143  ** Upload the config
144  Let's start with a file [[file:uploadCaddy.json][uploadCaddy.json]]
145  We can check that the config is valid using ~caddy validate~
146  #+name: validate config file
147  #+begin_src shell
148    caddy validate --config uploadCaddy.json
149  #+end_src
150  
151  #+RESULTS: validate config file
152  : Valid configuration
153  
154  We have started the *Caddy daemon* via ~caddy start~ with no config file.
155  This is fairly easy to check that there is no config applied:
156  #+name: running on empty
157  #+begin_src shell
158    curl localhost:2019/config/
159  #+end_src
160  
161  #+RESULTS: running on empty
162  : null
163  
164  Let's upload our config
165  #+name: upload config
166  #+begin_src shell
167    curl localhost:2019/load \
168         -H "Content-Type: application/json" \
169         -d @uploadCaddy.json
170  #+end_src
171  
172  #+RESULTS: upload config
173  
174  Let's confirm the current config
175  #+name: check current config
176  #+begin_src shell
177    curl localhost:2019/config/
178  #+end_src
179  
180  #+RESULTS: check current config
181  : {"apps":{"http":{"servers":{"example":{"listen":[":2015"],"routes":[{"handle":[{"body":"Hello, world!","handler":"static_response"}]}]}}}}}
182  
183  And if we curl the URL, we get
184  #+name: curling
185  #+begin_src shell
186    curl localhost:2015
187  #+end_src
188  
189  #+RESULTS: curling
190  : Hello, world!
191  
192  ** Replace/Update active config
193  Suppose we update the config file this ways:
194  #+begin_src js
195    { "handler": "static_response", "body": "I can do hard things!" }
196  #+end_src
197  
198  We update the Caddy's active config by running the same POST request:
199  #+name: update config
200  #+begin_src shell
201    curl localhost:2019/load \
202         -H "Content-Type: application/json" \
203         -d @uploadCaddy.json
204  #+end_src
205  
206  Always good to check
207  #+name: always good to check
208  #+begin_src shell
209    curl localhost:2019/config/
210  #+end_src
211  
212  #+RESULTS: always good to check
213  : {"apps":{"http":{"servers":{"example":{"listen":[":2015"],"routes":[{"handle":[{"body":"I can do hard things!","handler":"static_response"}]}]}}}}}
214  
215  and Indeed
216  #+name: check replace config
217  #+begin_src shell
218    curl localhost:2015
219  #+end_src
220  
221  #+RESULTS: check replace config
222  : I can do hard things!
223  
224  ** Config traversal
225  Instead of uploading the whole config, we can make change directly in
226  the POST request.
227  #+name: snipe config change
228  #+begin_src shell
229    curl \
230        localhost:2019/config/apps/http/servers/example/routes/0/handle/0/body \
231        -H "Content-Type: application/json" \
232        -d '"Work smarter, not harder"'
233  #+end_src
234  
235  #+RESULTS: snipe config change
236  
237  #+name: check snipe config
238  #+begin_src shell
239    curl localhost:2015
240  #+end_src
241  
242  #+RESULTS: check snipe config
243  : Work smarter, not harder
244  
245  #+name: jq to prettify outup
246  #+begin_src shell
247    curl localhost:2019/config/ | jq
248  #+end_src
249  
250  #+RESULTS: jq to prettify outup
251  #+begin_example
252  {
253    "apps": {
254      "http": {
255        "servers": {
256          "example": {
257            "listen": [
258              ":2015"
259            ],
260            "routes": [
261              {
262                "handle": [
263                  {
264                    "body": "Work smarter, not harder",
265                    "handler": "static_response"
266                  }
267                ]
268              }
269            ]
270          }
271        }
272      }
273    }
274  }
275  #+end_example
276  
277  ⚠️ The config file used is now not the current config in caddy. For
278  best practice, stick to one way of uploading and updating the config.
279  
280  ** Tagged json with @id
281  Adding a tag in part of the json config allow us to use shortcut to
282  access that part of the structure. We want something like
283  #+name: tagged json
284  #+begin_src js
285  {
286    "apps": {
287      "http": {
288        "servers": {
289          "example": {
290            "listen": [
291              ":2015"
292            ],
293            "routes": [
294              {
295                "handle": [
296                  {
297                    "@id": "msg",
298                    "body": "I can do hard things!",
299                    "handler": "static_response"
300                  }
301                ]
302              }
303            ]
304          }
305        }
306      }
307    }
308  }
309  #+end_src
310  
311  Let's add that tag via the API
312  #+name: tagging config
313  #+begin_src shell
314    curl \
315        localhost:2019/config/apps/http/servers/example/routes/0/handle/0/@id \
316        -H "Content-Type: application/json" \
317        -d '"msg"'
318  #+End_src
319  
320  #+RESULTS: tagging config
321  
322  Now we can access the tag directly
323  #+name: tag access
324  #+begin_src shell
325    curl localhost:2019/id/msg | jq
326  #+end_src
327  
328  #+RESULTS: tag access
329  : {
330  :   "@id": "msg",
331  :   "body": "Work smarter, not harder",
332  :   "handler": "static_response"
333  : }
334  
335  and make a targetted change accordingly
336  #+name: and harder
337  #+begin_src shell
338    curl \
339        localhost:2019/id/msg/body \
340        -H "Content-Type: application/json" \
341        -d '"Some shortcut are good"'
342  #+end_src
343  
344  #+RESULTS: and harder
345  
346  and check it again
347  #+name: check shortcut
348  #+begin_src shell
349    curl localhost:2015
350  #+end_src
351  
352  #+RESULTS: check shortcut
353  : Some shortcut are good
354  
355  * Caddyfile
356  ** HTTP vs HTTPS
357  Let's create a new *Caddyfile* with just an address
358  #+begin_src caddy
359    :2020
360  #+end_src
361  
362  We select the port ~2020~ to avoid the privileges required to use the
363  default ~443~.
364  
365  Run it with a shell command from the same folder as the Caddyfile by
366  using
367  #+begin_src shell
368    caddy run --watch
369  #+end_src
370  
371  The ~run~ is taking the foreground of the shell so that we can easily
372  stop it using ~Ctrl-C~. The ~--watch~ flag is to rerun automatically
373  the caddy shell every time the config file is updated.
374  
375  And to confirm that the server is running
376  #+name: test runner
377  #+begin_src shell
378    curl localhost:2019/config/ | jq
379  #+end_src
380  
381  #+RESULTS: test runner
382  #+begin_example
383  {
384    "apps": {
385      "http": {
386        "servers": {
387          "srv0": {
388            "listen": [
389              ":2020"
390            ]
391          }
392        }
393      }
394    }
395  }
396  #+end_example
397  
398  Pinging the URL of the server will return nothing. To add a reponse:
399  #+name: hello world
400  #+begin_src caddy
401    :2020
402  
403    respond "Hello, world!"
404  #+end_src
405  
406  Since the daemon is watching any changes in the Caddyfile, no need to
407  reload, we can ping the server directly:
408  #+name: ping 2
409  #+begin_src shell
410    curl localhost:2020
411  #+end_src
412  
413  #+RESULTS: ping 2
414  : Hello, world!
415  
416  If, in the config file, the site has an IP address or a host name,
417  caddy will serve over HTTPS by default. To force HTTP, either add the
418  protocol directly or just the port number:
419  - ~:2020~ :: Serves over ~http://localhost:2020~
420  - ~localhost:2020~ :: Serves over ~https://localhost:2020~
421    The shell will ask for the OS password for the first request.
422  - ~http://localhost:2020~ :: Serves over HTTP
423  ** Static file server
424  To have caddy serving directory listing use the ~file_server~ directive
425  #+begin_src caddy
426    localhost:2020
427  
428    file_server browse
429  #+end_src
430  
431  Opening a browser to ~https://localhost:2020/~ will display the
432  content of the directory
433  ** Templates evaluation
434  If we create an html file in the current folder and visit it
435  #+name: caddy.html
436  #+begin_src html
437    <!DOCTYPE html>
438    <html>
439      <head>
440        <title>Caddy tutorial</title>
441      </head>
442      <body>
443        Page loaded at: {{now | date "Mon Jan 2 15:04:05 MST 2006"}}
444      </body>
445    </html>
446  #+end_src
447  
448  Opening the browser and displaying ~https://localhost:2020/caddy.html~
449  will be verbatim.
450  To evaluate the template part, we should use the ~templates~ directive.
451  The Caddyfile becomes
452  #+name: Caddyfile
453  #+begin_src caddy
454    localhost:2020
455  
456    templates
457    file_server browse
458  #+end_src
459  
460  Lots of option available for caddy templates, see
461  https://caddyserver.com/docs/modules/http.handlers.templates
462  ** Compression
463  It's good practice to compress responses with a quick and modern
464  compression algorithm. See ~encode~ directive
465  https://caddyserver.com/docs/caddyfile/directives/encode
466  
467  #+name: Caddyfile
468  #+begin_src caddy
469    localhost:2020
470  
471    templates
472    encode
473    # Default value for encode omitted, same as
474    # encode zstd gzip
475    file_server browse
476  #+end_src
477  ** Multiple sites
478  
479  To collect multiple config across multiple sites within one single
480  Caddyfile we can wrap each config between {} following the format:
481  - only addresses appear outside of the braces
482  - only directives appear inside
483  
484  The current file becomes
485  #+name: Caddyfile
486  #+begin_src caddy
487  localhost:2020 {
488  	templates
489  	encode
490  	# Default value for encode omitted, same as
491  	# encode zstd gzip
492  	file_server browse
493  }
494  #+end_src
495  
496  and you can now add more than one site, base on their addresses:
497  #+name: multiple sites
498  #+begin_src caddy
499  :8080 {
500    respond "I am 8080"
501  }
502  
503  :8081 {
504    respond "I am 8081"
505  }
506  
507  :8082, 8083 {
508    respond "We share the same config"
509  }
510  #+end_src
511  ** Matchers
512  When we want a different behaviour for the same site but with
513  different request, we append matcher tokens to the directives.
514  Based on the request, we want:
515  - /api/ :: Send to the Back end
516  - * :: file server
517  
518  #+name: Caddyfile
519  #+begin_src caddy
520  localhost:2020 {
521  	reverse_proxy /api/* 127.0.0.1:9005
522  	templates
523  	encode
524  	# Default value for encode omitted, same as
525  	# encode zstd gzip
526  	file_server browse
527  }
528  #+end_src
529  
530  We can also name matcher using ~@name~
531  #+begin_src caddy
532  @postfoo {
533    method POST
534    path   /foo/*
535  }
536  
537  reverse_proxy @postfoo localhost:9000
538  #+end_src
539  
540  The directives have a predefined precedence order
541  https://caddyserver.com/docs/caddyfile/directives#directive-order This
542  order can be overwritten via the ~route~ directive that will follow
543  the directives verbatim
544  https://caddyserver.com/docs/caddyfile/directives/route#route
545  * Env Variables
546  The format for variables is ~{$value:default}~
547  They get substituted *before* the Caddyfile gets parsed.
548  #+begin_src shell
549    export SITE_ADDR=localhost:9005
550    caddy start
551  #+end_src
552  
553  The Caddyfile
554  #+begin_src caddy
555  {$SITE_ADDR} {
556    file_server
557  }
558  #+end_src
559  
560  becomes
561  #+begin_src caddy
562  localhost:9005 {
563    file_server
564  }
565  #+end_src
566  * Further reading
567  https://caddyserver.com/docs/caddyfile/patterns
568  https://betterstack.com/community/guides/web-servers/caddy/