/ 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/