ARTICLES
Using caddy go web server in your project
By me
Difference between standard web server and caddy
If we compare for example apache or nginx with caddy there’s some similar things like virtual host and certificates, but the way that caddy is working is quite different. Some of key highlights for caddy:
- Automatic TLS
- Very nice static performance when comparing to other alternatives
- Very common-sense config file you have ever seen, in v2 it’s even crazier!
- Markdown rendering
- Reverse proxy with load balancing, health checking, caching and more
- Kubernetes Ingress Controller
- Experimental QUIC support for cutting-edge transmissions
- HTTP/2 by default
- Extensible with plugins because a convenient web server is a helpful one
- Runs anywhere with no external dependencies (not even libc)
Caddy docker image
Like you have nginx and apache docker image there’s also caddy docker image, and it have 10M+ downloads: Caddy docker image.
Configuration
Things like sections and items are obsolete! Say hello to new, better way to construct config file - Caddyfile
mydomain.com
# Templates give static sites some dynamic features
templates
# Compress responses according to Accept-Encoding headers
encode gzip zstd
# Make HTML file extension optional
try_files {path}.html {path}
# Send API requests to backend
reverse_proxy /api/* localhost:9005
# Serve everything else from the file system
file_server
This starts caddy with file server, reverse proxy for /api/* path to localhost:9005 (like PHP or node.js), gzip encoding and site definition. Did you notice there’s no https in config? Well, caddy has it automatically! You can of course turn this off if you want to develop locally or if you don’t need https (why?). Caddy use internal letsencrypt certificate management, so you just need to run your site and caddy will do everything seamlessly for you! This is only web server that does this. Configuration for Caddy v1 and Caddy v2 is pretty much different but v2 have multiple adapters to chose from. Common way to configure v2 is by using http request with configuration parameters. This is pretty interesting as i never seen this in any other web server. Actually, this is quite useful especially in applications like cPanel that needs to reconfigure web server on the fly by sending http requests. Ofcourse, you can use same old Caddyfile but that file is internally converted to native one.
Using caddy as web server in your app
Finally, no need to use 3rd party web server to serve request - you can use caddy as your solution and write your code like Java developers use Tomcat. You have some guidelines here: Embedding Caddy in your Go program. Basically, you use caddy as go library (package) and you can start/stop/restart web server directly from your code so yes, there’s a complete control. If you want you can use JSON configuration instead of caddyfile by using caddyfile package for conversion.
Here’s a quick start
package main
import (
"github.com/caddyserver/caddy"
_ "github.com/caddyserver/caddy/caddyhttp"
"log"
)
func main() {
caddy.AppName = "MyCaddyApp"
caddy.AppVersion = "0.1a"
// pass in the name of the server type this Caddyfile is for (like "http")
caddyfile, err := caddy.LoadCaddyfile("http")
if err != nil {
log.Fatal(err)
}
instance, err := caddy.Start(caddyfile)
if err != nil {
log.Fatal(err)
}
// Start() only blocks until the servers have started.
// Wait() blocks until the servers have stopped.
instance.Wait()
}
Note that at the time of writing this article you will need go 1.13 as crypto/ed25519 package is available in 1.13 and it’s used by one of the dependencies. Also note that “Embedding Caddy in your Go program” is written 3 years ago so package is renamed from mholt/caddy to caddyserver/caddy. You need to update code from this page to work. Now you need to create plugin. Plugin is go package. You need to import caddy package and register your plugin.
import "github.com/caddyserver/caddy"
func init() {
caddy.RegisterPlugin("gizmo", caddy.Plugin{
ServerType: "http",
Action: setup,
})
}
func setup(c *caddy.Controller) error {
return nil
}
You can now start to write your plugin. Take a look at manual how to write plugin