| 1 | --- |
| 2 | title: "Moving from nginx to Caddy" |
| 3 | date: 2023-09-03T13:00:00+03:00 |
| 4 | description: "I describe my journey into using Caddy and the great config truncation from 2000+ lines by 20x" |
| 5 | tags: [site, news] |
| 6 | type: blog |
| 7 | draft: false |
| 8 | --- |
| 9 | |
| 10 | # Backstory |
| 11 | I've heard of [Caddy](https://caddyserver.com/) for a long while, but have always been dismissive about it - ignoring it as "yet another webserver software" when I had my |
| 12 | perfectly good trusty nginx to rely on for many years already. Over the years, my nginx config has become somewhat bloated and even take a while |
| 13 | to do restarts on due to the complexity of said config. I did attempt to resolve it by reducing amount of expensive routines - which did help to |
| 14 | an extent - I was complacent with my setup. Until I took a deeper dive into Caddy. |
| 15 | |
| 16 | One Saturday night (...yesterday as of writing this post), BieHDC brought to my attention that Caddy has a nginx configuration adapter. |
| 17 | I thought to myself why not try it out if it's really plug-and-play and try to see what all the fuss is about. What followed this was all worth it. |
| 18 | |
| 19 | ## The nginx-adapter |
| 20 | I started off with building the [nginx adapter for Caddy](https://github.com/caddyserver/nginx-adapter) which took a while. |
| 21 | Very quickly after building it, I ran into issues - no matter what I did, I kept getting null routes on the generated output with no idea where it's coming from. |
| 22 | You would think I would have stopped here, but I foolishly tried to make it work for something that was never meant to be, you see, I forgot to do |
| 23 | one key thing before even starting this whole thing - RTFM (Read The Fucking Manual). The README had a list of directives it supported and I had a ton of which |
| 24 | were not supported, but very essential to the work of my services. |
| 25 | |
| 26 | I shelved the nginx-adpater for good at this point, after wasting an hour with it. |
| 27 | |
| 28 | ## The story doesn't end |
| 29 | While I may have been burnt by the mischiefs of nginx-adapter, I wasn't ready to give up - by this point I had already familiarised myself with Caddy's |
| 30 | documentation and reference syntax. I decided to give it a try for based.quest at very least to have a fair and honest impression of Caddy as a software |
| 31 | so I wouldn't start to bash on it going forward from a bad experience on a beta-phase config adapter. |
| 32 | |
| 33 | In literally a few minutes, I had made it, the Caddyfile for based.quest - I present it to you in all its glory in this blogpost: |
| 34 | ``` |
| 35 | http://based.quest, based.quest { |
| 36 | root * /var/www/based.quest/html |
| 37 | file_server |
| 38 | } |
| 39 | |
| 40 | breezewiki.based.quest { |
| 41 | reverse_proxy localhost:10416 |
| 42 | } |
| 43 | |
| 44 | rimgo.based.quest { |
| 45 | reverse_proxy localhost:3000 |
| 46 | } |
| 47 | |
| 48 | proxitok.based.quest { |
| 49 | reverse_proxy localhost:8999 |
| 50 | } |
| 51 | |
| 52 | quetre.based.quest { |
| 53 | reverse_proxy localhost:3333 |
| 54 | } |
| 55 | ``` |
| 56 | |
| 57 | Yes, you are seeing this right - **this little configuration only needed**. I was shocked. All this time I had been writing more for no reason, because I |
| 58 | turned a blind eye to the alternative that was right in front of me for many years - I've seen the name, I've seen it used in several applications that |
| 59 | I host under Docker, but never gave it a shot until it was pointed out to me that an adapter exist to load nginx configs (which obviously didn't work out, but |
| 60 | that's beside the point). |
| 61 | |
| 62 | ## The main server |
| 63 | I wasn't going to stop with only based.quest server - after seeing the potential, I took on the seemingly herculean task of porting my main server's 2000+ lines |
| 64 | of nginx config to a Caddyfile. I delved into documentation for over an hour, searching for answers for any immediate question I had. |
| 65 | |
| 66 | You may find what I wrote useful for your own configs, so here are (not fully mine) templates you can use for building your own Caddy virtualhosts: |
| 67 | ``` |
| 68 | (errors) { |
| 69 | handle_errors { |
| 70 | @custom_err file /err-{err.status_code}.html /err.html |
| 71 | handle @custom_err { |
| 72 | rewrite * {file_match.relative} |
| 73 | file_server |
| 74 | } |
| 75 | respond "{err.status_code} {err.status_text}" |
| 76 | } |
| 77 | } |
| 78 | (php-fpm) { |
| 79 | encode gzip |
| 80 | php_fastcgi unix//run/php/php7.4-fpm.sock { |
| 81 | try_files {path} {path}/index.php =404 |
| 82 | } |
| 83 | file_server |
| 84 | } |
| 85 | (cache-static) { |
| 86 | @static { |
| 87 | file |
| 88 | path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 |
| 89 | } |
| 90 | header @static Cache-Control max-age=1209600 |
| 91 | } |
| 92 | ``` |
| 93 | You can find most of this on the official documentation, but thought it may be useful to consolidate it here for your convenience. |
| 94 | |
| 95 | Migrating Matrix is super easy, but be attentive to details, they provide the Caddyfile samples on their own repository already - here is my final variant of it: |
| 96 | ``` |
| 97 | http://cernodile.com, cernodile.com, cernodile.com:8448 { |
| 98 | header /.well-known/matrix/* Content-Type application/json |
| 99 | header /.well-known/matrix/* Access-Control-Allow-Origin * |
| 100 | respond /.well-known/matrix/server `{"m.server": "cernodile.com"}` |
| 101 | respond /.well-known/matrix/client `{"m.homeserver":{"base_url":"https://cernodile.com"}}` |
| 102 | reverse_proxy /_matrix/* localhost:8008 |
| 103 | reverse_proxy /_synapse/* localhost:8008 |
| 104 | # [...] |
| 105 | } |
| 106 | ``` |
| 107 | |
| 108 | The reason I ask you to be attentive to details is because I broke my federation with it. Notice the /matrix/server field. I had copied the sample from Synapse |
| 109 | repository and left it as `"cernodile.com:443"` whereas my **original** well-known record was just `"cernodile.com"`. |
| 110 | |
| 111 | There were 2 blockers when migrating my services to Caddy. PeerTube and Gitweb. Unfortunately for PeerTube, since [PeerTube does not support anything else than nginx](https://docs.joinpeertube.org/install/any-os#webserver), |
| 112 | I had to keep one nginx virtualhost up and use reverse_proxy directive against it. As for Gitweb which doesn't supply any other configuration than |
| 113 | for Apache, I did manage to port it over to Caddy by adapting generic fastcgi adapter in a way that works for Gitweb, feel free to use it as well: |
| 114 | ``` |
| 115 | git.based.quest { |
| 116 | root * /usr/share/gitweb |
| 117 | try_files {uri} index.cgi |
| 118 | handle /static/* { |
| 119 | file_server |
| 120 | } |
| 121 | reverse_proxy unix//var/run/fcgiwrap.socket { |
| 122 | transport fastcgi { |
| 123 | env GITWEB_CONFIG /etc/gitweb.conf |
| 124 | split .cgi |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | ``` |
| 129 | |
| 130 | ## Closing thoughts |
| 131 | After all this effort, I am down to 108 lines on my Caddyfile from 2000+ lines on nginx. The performance is as great as ever with no hickups noticed. |
| 132 | I want to thank BieHDC for bringing this to my attention, I wouldn't have probably gone down this rabbit hole if it weren't for the nginx adapter. |
| 133 | This experience was all the worth it and I suggest you give Caddy a try if you are currently running an nginx site - you won't regret having to write |
| 134 | 20x less configuration for your webserver. |
| 135 | |
| 136 | Thank you for reading |
| 137 | - Cernodile |