···36363737##### NGINX Service Configuration Ownership
38383939-As my homelab continues to grow I have gravitated towards each Stack owning its own configuration. Through mechanisms like `environment` in `compose.yaml` or configs committed to git alongside `compose.yaml` etc., having the service-as-code live next to all the data needed run the service makes it more portable and reduces the cognitive scope required to configure it. NGINX config files need to be physically accessible to it and that is not a *feasible* option when services run on other hosts.
3939+As my homelab continues to grow I have gravitated towards each Stack owning its own configuration. Through mechanisms like `environment` in `compose.yaml` or configs committed to git alongside `compose.yaml` etc., having the service-as-code [live next to all the data needed run the service](#dynamic-label) makes it more portable and reduces the cognitive scope required to configure it. NGINX config files need to be physically accessible to it and that is not a *feasible* option when services run on other hosts.
40404141##### SWAG is Tightly Coupled and Opinionated
42424343LSIO does an excellent job making setup with NGINX easy by using [SWAG](https://docs.linuxserver.io/general/swag/). For simple setups and users just dipping their toes into the space it's a fantastic tool for getting started quickly without requiring any hand-holding.
44444545-However, it has shortfalls which appear for more complex use-cases. Some of these are limitations of nginx, such as needing the user to [edit .ini files for DNS ACME challenge, while other solutions only need ENVs](http://localhost:4000/posts/migrating-to-traefik/#wildcards).
4545+However, it has shortfalls which appear for more complex use-cases. Some of these are limitations of nginx, such as needing the user to [edit .ini files for DNS ACME challenge, while other solutions only need ENVs](#wildcards).
46464747Others are due to the reality of limited developer-hours needing to fulfill only the most common use-case, like LSIO's [cloudflare docker mod](https://github.com/linuxserver/docker-mods/tree/universal-cloudflared) configuration only working with one domain even though a tunnel can be used for multiple domains -- one domain is the most common use-case and easiest to script for. In this scenario, "fixing" the problem means refactoring the entire stack to remove universal-cloudflare and implementing your own `cloudflared` container.
48484949If most scenarios end with the user having to implement the decoupled solution anyway...why not consider other reverse proxy solutions since we aren't tied to SWAG anymore?
5050+5151+##### SWAG Cert Management Feels Bad
5252+5353+I'll admit this is entirely personal opinion. SWAG has two ENVs used for configuring a cert *for a first domain:* `URL` and `SUBDOMAINS`.
5454+5555+```yaml
5656+environment:
5757+ URL: yourdomain.url
5858+ SUBDOMAINS: www,example1,example2
5959+```
6060+{: file="compose.yaml"}
6161+6262+To add additional domains (with their subdomains) you need to use a third ENV that combines both in away that you would have assumed the original ENVs could have been used:
6363+6464+```diff
6565+environment:
6666+ URL: yourdomain.url
6767+ SUBDOMAINS: www,example1,example2
6868++ EXTRA_DOMAINS: yourdomainfoo.url,yourdomainbar.url,sub1.yourdomainbar.url
6969+```
7070+{: file="compose.yaml"}
7171+7272+Why isn't the syntax for `EXTRA_DOMAINS` the way "everything" works? I imagine it's a backward compatibility thing but it rubs me the wrong way.
7373+7474+Additionally, to change this generating a wildcard cert all of the ENVs need to change...again.
7575+7676+```diff
7777+environment:
7878+ URL: yourdomain.url
7979+- SUBDOMAINS: www,example1,example2
8080++ SUBDOMAINS: wildcard
8181+- EXTRA_DOMAINS: yourdomainfoo.url,yourdomainbar.url
8282++ EXTRA_DOMAINS: yourdomainfoo.url,*.yourdomainfoo.url,yourdomainbar.url,*.yourdomainbar.url
8383+```
8484+{: file="compose.yaml"}
8585+8686+It's not exactly *complex* but it definitely isn't intuitive either. Compare this to how [Traefik does it, either automatically or with idiomatic YAML config.](#cert-management)
8787+8888+Traefik also has the advantange of being able to configure [DNS challenge provider via ENV](#wildcards) while SWAG requires finding an [`.ini` file](https://github.com/linuxserver/docker-swag/tree/master/root/defaults/dns-conf) in the SWAG service's [config directory](https://docs.linuxserver.io/general/swag/#docker-compose), and then [editing the file to hardcode our DNS provider's credentials.](https://github.com/linuxserver/docker-swag/blob/master/root/defaults/dns-conf/cloudflare.ini)
50895190##### Lack of Dashboard
5291···284323285324### Cert Management
286325287287-Both SWAG and Traefik offer automated SSL cert generation but I found Traefik's setup to be vastly easier to understand and configure than SWAGs.
326326+Both SWAG and Traefik offer automated SSL cert generation but I found Traefik's setup to be vastly easier to understand and configure [than SWAGs.](#swag-cert-management-feels-bad)
288327289289-For a simple setup, say one domain + subdomain using http verification, both providers are moderately equivalent. SWAG does everything using [container ENVs](https://docs.linuxserver.io/general/swag/#create-container-via-http-validation) which is attractive.
328328+For a simple setup, say one domain + subdomain using *http verification*, both providers are moderately equivalent. SWAG does everything using [container ENVs](https://docs.linuxserver.io/general/swag/#create-container-via-http-validation) which is attractive.
290329291330Traefik requires setting up a [cert resolver and entrypoint](https://doc.traefik.io/traefik/https/acme/#configuration-examples) which can be done via file or as labels on a docker container (not recommended).
292331···300339301340on a docker container then Traefik will automatically get a cert for `example.com`. That's pretty nice.
302341303303-To do the same with SWAG you need to define ENVs for a main URL/domain, all subdomains, and `EXTRA_DOMAIN` for all additional domains:
304304-305305-```yaml
306306-environment:
307307- URL: yourdomain.url
308308- SUBDOMAINS: www,example1,example2
309309- EXTRA_DOMAINS: yourdomainfoo.url,yourdomainbar.url
310310-```
311311-{: file="compose.yaml"}
312312-313313-It's...weird to need two different ENVs to define domains.
314314-315342#### Wildcards
316343317317-But this is where Traefik really shines. To use wildcard certs with Traefik, we add a few more lines to our existing [static config](#static-file), specifying the dns challenge provider and explicitly defining the domains:
344344+This is where Traefik really shines. To use wildcard certs with Traefik, we add a few more lines to our existing [static config](#static-file), specifying the dns challenge provider and explicitly defining the domains:
318345319346```diff
320347entryPoints
···356383```
357384{: file="compose.yaml" link="https://github.com/FoxxMD/traefik-homelab/blob/main/traefik_internal/compose.yaml#L14"}
358385359359-To setup wildcards with SWAG we need to modify service ENVs
360360-361361-```diff
362362-environment:
363363- URL: yourdomain.url
364364-- SUBDOMAINS: www,example1,example2
365365-+ SUBDOMAINS: wildcard
366366-- EXTRA_DOMAINS: yourdomainfoo.url,yourdomainbar.url
367367-+ EXTRA_DOMAINS: yourdomainfoo.url,*.yourdomainfoo.url,yourdomainbar.url,*.yourdomainbar.url
368368-+ VALIDATION=dns
369369-```
370370-{: file="compose.yaml"}
371371-372372-then find our provider's [`.ini` file](https://github.com/linuxserver/docker-swag/tree/master/root/defaults/dns-conf) in the SWAG service's [config directory](https://docs.linuxserver.io/general/swag/#docker-compose), and [edit the file to hardcode our DNS provider's credentials.](https://github.com/linuxserver/docker-swag/blob/master/root/defaults/dns-conf/cloudflare.ini)
373373-374374-I don't particularly like having credentials hardcoded like that and `EXTRA_DOMAINS` still feelsbadman.jpg
375375-386386+And that's it! Compare this to the [wildcard setup required for SWAG](#swag-cert-management-feels-bad)...Traefik feels easier.
376387377388#### Cloudflare Tunnels {#certs-and-cf-tunnels}
378389···739750* [`universal-cloudflared`](https://github.com/linuxserver/docker-mods/tree/universal-cloudflared) - Installs `cloudflared` directly into the SWAG container and uses `CF_*` ENVs to automate setup via CLI (or `CF_REMOTE_MANAGE_TOKEN` to pull config from CF dashboard)
740751* [`cloudflare_real-ip`](https://github.com/linuxserver/docker-mods/tree/swag-cloudflare-real-ip) - pulls CF edge server IPs into a list that Nginx can use. It also requires adding a few Nginx directives to your config in order to use this list to set real IP.
741752742742-We can achieve the same as above by setting up `cloudflared` as its own container and using a the [traefik plugin](https://doc.traefik.io/traefik/plugins/) [cloudflarewarp](https://github.com/PseudoResonance/cloudflarewarp) to parse CF edge server IPs.
753753+We can achieve the same as above, for Traefik, by setting up `cloudflared` as its own container and using a the [traefik plugin](https://doc.traefik.io/traefik/plugins/) [cloudflarewarp](https://github.com/PseudoResonance/cloudflarewarp) to parse CF edge server IPs.
743754744755#### `cloudflared` Tunnel Container Setup
745756