themepark-dev / theme.park

A collection of themes/skins for 50 selfhosted apps!
https://theme-park.dev
MIT License
2.31k stars 772 forks source link

docs: add caddy v2 example #59

Closed jef closed 4 years ago

jef commented 4 years ago

Description

We should add documentation for Caddyfiles in caddy v2 and how-to install. Once I figure it out, I will update.

GilbN commented 4 years ago

Awesome, thanks!

jef commented 4 years ago

Not sure if it's possible as easily as v1, considering the http.filter plugin was pretty dang good. I don't know if I want to fiddle around with this as much as the next person, so maybe we'll wait for some help.

Nosirus commented 4 years ago

there is an alternative, but I haven't looked into it.

github.com/sjtug/caddy2-filter

jef commented 4 years ago

Cool, I could give that a go soon! I'll report back.

jef commented 4 years ago

Since I run caddy in Docker, they have a section called Adding custom Caddy modules. I created a new Dockerfile with github.com/sjtug/caddy2-filter and built the image. Deployed and it works great.

FROM caddy:2.0.0-builder AS builder

RUN caddy-builder \
    github.com/sjtug/caddy2-filter

FROM caddy:2.0.0

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Then a simple docker build -t caddy:latest . and then start it back up!

If you don't use Caddy in Docker, take a look at Extending Caddy.

My Caddyfile looks something like this:

{
    order filter after encode
}

sonarr.domain.com {
    encode zstd gzip
    reverse_proxy sonarr:8989 {
        header_up -Accept-Encoding
    }
    filter rule {
        content_type text/html.*
        search_pattern </head>
        replacement "<link rel='stylesheet' type='text/css' href='https://gilbn.github.io/theme.park/CSS/themes/sonarr/space-gray.css'></head>"
    }
}

Then running docker exec -it caddy caddy validate --config /etc/caddy/Caddyfile to validate the results gave me:

2020/07/13 22:59:51.510 INFO    using provided configuration    {"config_file": "/etc/caddy/Caddyfile", "config_adapter": ""}
2020/07/13 22:59:51 [INFO][cache:0xc0007ef7c0] Started certificate maintenance routine
2020/07/13 22:59:51.512 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2020/07/13 22:59:51.512 INFO    http    enabling automatic HTTP->HTTPS redirects    {"server_name": "srv0"}
2020/07/13 22:59:51.519 INFO    tls setting internal issuer for automation policy that has only internal subjects but no issuer configured  {"subjects": ["localhost"]}
2020/07/13 22:59:51 [INFO][cache:0xc0007ef7c0] Stopped certificate maintenance routine
Valid configuration

All looks good from there! Only problem is that it didn't work when I went to go visit Sonarr :disappointed:

We're getting close, just need to do some more troubleshooting.

Nosirus commented 4 years ago

just "filter" not "filter rule" :)

but I'm stuck on proxy_hide_header "x-webkit-csp"; proxy_hide_header "content-security-policy"; for qbittorrent any idea ?

jef commented 4 years ago

WHOOPS! Wow, thanks @Nosirus. I'm glad I posted my config so someone could correct me. I also use qBittorrent, so I'll keep you posted if I figure it out.

jef commented 4 years ago

Figured it out, @Nosirus. You're looking for header_down.

Use something like this:

qbittorrent.domain.com {
    encode zstd gzip
    reverse_proxy qbittorrent:25832 {
        header_up -Accept-Encoding
        header_down -x-webkit-csp
        header_down -content-security-policy
    }
    filter {
        content_type text/html.*
        search_pattern </head>
        replacement "<link rel='stylesheet' type='text/css' href='https://gilbn.github.io/theme.park/CSS/themes/qbittorrent/space-gray.css'></head>"
    }
}
jef commented 4 years ago

@gilbN, this might be enough information for you to put into the Wiki. If you'd like me to write up something more formal and put it as a comment, let me know! Otherwise, @Nosirus, thanks for the heads up on the filter!

GilbN commented 4 years ago

Nice work! Check out https://caddyserver.com/docs/caddyfile/directives/header And see if you can strip it. Or add a working csp rule Edit : didn't see the last comment

GilbN commented 4 years ago

@gilbN, this might be enough information for you to put into the Wiki. If you'd like me to write up something more formal and put it as a comment, let me know! Otherwise, @Nosirus, thanks for the heads up on the filter!

If you want to do a write up that would be great! Thanks

jef commented 4 years ago

Caddy v2

We rely on sjtug's caddy2-filter as Caddy v2 does not have filtering as of now.

There are two ways to extend Caddy:

Docker

You will have to create your own Caddy image that includes the caddy2-filter.

Dockerfile:

FROM caddy:2.0.0-builder AS builder

RUN caddy-builder \
    github.com/sjtug/caddy2-filter

FROM caddy:2.0.0

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Then run docker build -t caddy:latest . to build the image. After we update the Caddyfile below, we can (re)start the container by running docker run -d -p 80:80 -p 443:443 caddy:latest as an example.

Bare metal

Make sure you install xcaddy to add modules to Caddy.

Then install the caddy2-filter module by using:

xcaddy build \
    --with github.com/sjtug/caddy2-filter

You can confirm the module is available by using xcaddy list-modules.

Updating the Caddyfile

Almost like Caddy v1, here is an example filter we need to include in the all the services we want themed:

filter {
    content_type text/html.*
    search_pattern </head>
    replacement "<link rel='stylesheet' type='text/css' href='https://gilbn.github.io/theme.park/CSS/themes/<APP_NAME>/<THEME>.css'></head>"
}

With caddy2-filter, we need to also add this option in the global option block:

{
    order filter after encode
}

And if you're using a reverse proxy, you also need to include header_up -Accept-Encoding in the reverse_proxy directive body.

Full example of a Caddyfile ``` { order filter after encode } radarr.example.com { encode zstd gzip reverse_proxy 127.0.0.1:7878 { header_up -Accept-Encoding } filter { content_type text/html.* search_pattern replacement "" } } ```

:point_right: If your service requires you to ignore a header, use the header_down subdirective in the reverse_proxy directive. For example, qBittorrent usage would look like this:

reverse_proxy 127.0.0.1:8080 {
    header_up -Accept-Encoding
    header_down -x-webkit-csp
    header_down -content-security-policy
}

Feel free to make any adjustments! Thanks everyone for the help!

Also for reference: Caddy v2 structure

GilbN commented 4 years ago

Thanks! Great work.

kwkaiser commented 4 years ago

Great research fellas; this thread helped me out a lot.

I did notice one thing about sjtug's filter implementation; it's not available as a reverse_proxy subdirective (even if you change the ordering in the global options to have it come after the reverse_proxy directive). Fortunately, there's a pretty simple work around using caddy's /route option, which will allow you to have subfolder-specific filters within a specific subdomain. I was able to get an example working with radarr / sonarr and the relevant CSS themes using this Caddyfile:

{
    order filter after encode
}

subdomain.mywebsite.com {
    encode zstd gzip

    route /radarr* {

        filter {
            content_type text/html.*
            search_pattern </head>
            replacement "<link rel='stylesheet' type='text/css' href='https://gilbn.github.io/theme.park/CSS/themes/radarr/plex.css'></head>"
        }

        reverse_proxy /radarr* http://radarr:7878 {
            header_up -Accept-Encoding
            header_down -x-webkit-csp
            header_down -content-security-policy
        }

    }

    route /sonarr* {
        filter {
            content_type text/html.*
            search_pattern </head>
            replacement "<link rel='stylesheet' type='text/css' href='https://gilbn.github.io/theme.park/CSS/themes/sonarr/plex.css'></head>"
        }

        reverse_proxy /sonarr* http://sonarr:8989 {
            header_up -Accept-Encoding
            header_down -x-webkit-csp
            header_down -content-security-policy
        }
    }
}

A thing worth noting are that the order of the filter and proxy within the /route directive is important; I wasn't able to get it to work properly unless the filter came before the proxy block.

jef commented 4 years ago

it's not available as a reverse_proxy subdirective

Thanks for the input! This is worth putting into the wiki as I don't use subfolders, so I didn't do any testing there.

As for the route and reverse_proxy, I think maybe you'd want to do something like /radarr/* instead of /radarr* only because if you type in /radarrrsomethingrrrr you'll still get redirected. That could be something the user wants though -- just pointing out!