Plex, Jellyfin, Nextcloud with Cloudflare

1. Caddy version (caddy version):

v2.0

2. How I run Caddy:

<! Docker—>

a. System environment:

b. Command:


c. Service/unit/compose file:

version: "3.7"
services:

  caddy:
    image: caddy
    container_name: caddy
    hostname: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "3000:3000"
      - "2023:2023"
      - "2024:2024"
      - "8126:8126"
      - "2003:2003"
      - "8125:8125"
      - "8083:8083"
      - "8082:8082"
      - "8125:8125"
      - "90:80"
      - "25826:25826"
      - "8086:8086"
      - "8090:8090"
      - "8094:8094"
      - "9090:9090"
      - "9103:9103"
      - "9100:9100"
    environment:
      - MY_DOMAIN
      - CLOUDFLARE_API_TOKEN
    volumes:
      - /opt/docker/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - /opt/docker/caddy/data:/data
      - /opt/docker/caddy/config:/config

networks:
  default:
    external:
      name: $DOCKER_MY_NETWORK

d. My complete Caddyfile or JSON config:

{
    # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}


(webconf) {
    # Add zstd and gzip compression to requests
    encode zstd gzip

    # Remove headers (leading "-")
    header {
        -x-powered-by
    }
}

# Add common headers for non-reverse_proxy sites
(non_reverse_proxy_headers) {
    header {
        Strict-Transport-Security "max-age=31536000;"
        X-Content-Type-Options    "nosniff"
        X-XSS-Protection          "1; mode=block"
        X-Frame-Options           "SAMEORIGIN"
        Referrer-Policy           "strict-origin-when-cross-origin"
        Content-Security-Policy   "frame-src 'self'; frame-ancestors 'self'; object-src 'none';"
    }

    @cache_css_js {
        path_regexp cache_css_js \.(?:css|js)$
    }
    @cache_media {
        path_regexp cache_media \.(?:jpg|jpeg|gif|png|bmp|ico|swf|xml|ogg|m4a|mp3)$
    }
    # 1 week
    header @cache_css_js Cache-Control max-age=604800
    # 2 weeks
    header @cache_media Cache-Control max-age=1209600
}


cloud.{$MY_DOMAIN} {
    reverse_proxy nextcloud:80
    header Strict-Transport-Security max-age=31536000;
    redir /.well-known/carddav /remote.php/carddav 301
    redir /.well-known/caldav /remote.php/caldav 301
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    import webconf
}


# external services
#
jellyfin.{$MY_DOMAIN} {
    reverse_proxy 192.168.1.97:8096
    import non_reverse_proxy_headers
    import webconf
}


plex.{$MY_DOMAIN} {
    reverse_proxy 192.168.1.97:32400
    import non_reverse_proxy_headers
    import webconf
}

:8096 {
    reverse_proxy 192.168.1.97:8096
}

:32400 {
    reverse_proxy 192.168.1.97:32400
}

3. The problem I’m having:

Most of my docker services are working.
However, Plex Media Sever is an external service (non-Docker) and whenever I type in plex.mydomain.com, it’s doesn’t get the certificate.
Second issue is my Jellyfin is also an external service and it redirect to www.jellyfin.mydomain instead htttps. If I type in https://jellyfin.mydomain.com, then it works fine.

4. Error messages and/or full log output:

Plex Media Server error:

Your connection to this site isn't secure.

5. What I already tried:

6. Links to relevant resources:

With the help of the above tutorial, I’ve just migrated my services from Traefik to Caddy.

Do I need to add a ‘transparent’ directive or something to fix this ?

Thanks in advance

You didn’t completely fill out the thread template so we can’t effectively help you. We need to know what your config looks like, what errors you’re seeing exactly, what’s in your logs, etc.

Hi,
I just updated the template.

Plex network settings:

Hello,

Anybody can help me ?

Hi @tx7,

Those settings involve giving a certificate file to plex.tv itself. Presumably you would then point your domain at Plex’s own servers. This would mean you don’t need Caddy at all for your Plex site.

Is that what you’re trying to achieve here?

Hello,

No, I want my Plex subdomain to has certificate file.

Had a closer look, I had presumed incorrectly.

Either way, you don’t need those certificate settings in Plex, although you can use them.

Can you give us the output from this command: curl -kIL plex.example.com

are you referred cert settings in the Plex network settings ?

curl output:

curl: (7) Failed to connect to plex.example.com port 80: Connection refused

This is the error when I browse to my Plex subdomain:

  Attackers might be trying to steal your information from plex.mydomain.com (for example, passwords, messages, or credit cards).
   NET::ERR_CERT_COMMON_NAME_INVALID

Yes, they should be unnecessary. You can set them, but you can also have Caddy proxy to it without bothering.

Is port 80 open?

Hmm, this must be a rare one for Caddy. It is designed to refuse to give you a cert at all if it doesn’t have a matching cert, it shouldn’t give you an incorrect one.

Add debug to the global options of your Caddyfile, start Caddy, then run on the command line:

curl -kIL https://plex.example.com

Then, tell us what the output from Caddy is.

For plex, you don’t want to use a Custom certificate domain as you just want to fill in the custom URL:

You should try first without CloudFlare in the mix and validate things work. If things work, you can move on to CloudFlare as that’s changing your DNS and making sure CloudFlare is setup right.

I currently set Plex domain to use as ‘DNS Only’ in Cloudflare.
I’ve tried to remove the Custom cert domain as well, but same error.

How do I add debug option in Caddyfile ?

Port 80 is opened:

   lsof -i :80
  COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
 Plex\x20T 5710 plex   77u  IPv4   44340      0t0  TCP server.localhost:38620->ec2-99-80-231- 
 223.eu-west-1.compute.amazonaws.com:http (CLOSE_WAIT)

 Plex\x20D 5711 plex   77u  IPv4   44340      0t0  TCP server.localhost:38620->ec2-99-80-231- 
 223.eu-west-1.compute.amazonaws.com:http (CLOSE_WAIT)

docker-pr 8926 root    4u  IPv6 3573603      0t0  TCP *:http (LISTEN)



curl -kIL https://plex.mydomain.com
HTTP/2 401
cache-control: no-cache
content-security-policy: frame-src 'self'; frame-ancestors 'self'; object-src 'none';
content-type: text/html
date: Fri, 26 Jun 2020 22:55:31 GMT
referrer-policy: strict-origin-when-cross-origin
server: Caddy
strict-transport-security: max-age=31536000;
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-plex-protocol: 1.0
x-xss-protection: 1; mode=block
content-length: 193

I’m having a hard time following as I can’t tell if you are masking what domain you are using or not.

If we’re talking about certificates, why are we checking port 80 as we should be checking https on port 443.

You should have caddy running and 443 should be listening:

felix@gemini:~$ netstat -an | grep 443 | grep LISTEN
tcp6       0      0 :::443                  :::*                    LISTEN

and you should be able to connect to that host via name https://plex.domain.com

I was doing the test for Whitestrake.
Yes, I was masking my domain.

tcp6       0      0 :::443                  :::*                    LISTEN
unix  2      [ ACC ]     STREAM     LISTENING     901484   @/containerd- 

shim/moby/042dca55608f2e68b02d357024884439e8a2477da717529495ebda2a3e692a9b/shim.sock@

What’s the error when you hit your https site?

I think figured out the issue.

When I entered the url: https://plex.mydomain.com:32400, I received this error:

    Your connection isn't private
    Attackers might be trying to steal your information from plex.mydomain.com (for example, 
    passwords, messages, or credit cards).
    NET::ERR_CERT_COMMON_NAME_INVALID

However, if I just enter the url without the port number 32400, I got a valid LetsEncrypt cert and access the site normally.

 This application is at plex.mydomain.com and is not hosted by Plex. Continue only if you recognize this server and wish to grant access.

Correct, that’s why I asked you to enter the custom URL in there on port 443 as that’s what you have setup in Caddy.

Happy it’s working :slight_smile:

Thanks for the help guys.