After spending a good chunk of time on my Home Cluster, I’ve gotten to the point where almost everything is up and running and I wanted to take a moment to document how it’s all tied together.
Internet (80/443)
|||| +------------------+
vvvv | cluster{N} |
+-------------+ | - consul |
| Router | | - nomad |
| \-> nginx ------> - container(s) |
+---------^---+ | - +---------------------------+
| +-----| router-updater |
| | - consul-template |
| | |_ service change |
| | |_ render nginx.conf |
| | |_ push nginx.conf |
| +----------------------v----+
\-----------------------------------/
Sweet ASCII art, bruh!
Essentially, the internet comes to my house address (yay dns and static IPs) and enters my router. The router has a port forwarding setup to redirect port 80/443 to an nginx instance listening on 8080/8443. nginx then proxies the request, based on host header, to a container on one of the cluster machines.
The nginx config is managed by a router-updater
container which is constantly watching where the cluster for changes and pushing updates to the router’s nginx instance. Ideally, this consul-template
instance would have lived on the router, but the go
application isn’t compatible with the router’s architecture, c’est la vie.
The nginx consul template looks something like this:
# jrmcc
{{- $service := service "jrmcc" }}
{{- if $service }}
upstream jrmcc {
{{- range $service }}
server {{ .Address }};
{{- end }}
}
server {
listen 8080;
server_name jrm.cc;
location / {
proxy_pass http://jrmcc;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
{{ else }}
# Warning, no healthly 'jrmcc' found in service list
{{ end }}