Post

Plex - Selfhosted Media Server

Plex - Selfhosted Media Server

Plex (Plex Media Server) is free software that allows users to create a client–server for movies, television shows, and music. Free Plex accounts can share personal media libraries among a user’s own collection of devices or with friends. Plex Media Server organizes movie and television content and adds posters, plot summaries, cast and crew lists, technical details, critical reviews, and subtitles.

Since this uses media from my NAS i have simply decided to run this as a Docker Container on UnRAID on my NAS instead of having it as part of my kubernetes cluster to remove the need to access the NAS media remotely

Kubernetes Manifest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: plex
    app.kubernetes.io/instance: plex
    app.kubernetes.io/name: plex
  name: plex
  namespace: plex
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: plex
  template:
    metadata:
      labels:
        app: plex
        app.kubernetes.io/name: plex
    spec:
      nodeSelector:
        nas: "true"
      containers:
      - image: linuxserver/plex
        name: plex
        ports:
          - containerPort: 32400
            hostPort: 32400
            protocol: TCP
          - containerPort: 32400
            hostPort: 32400
            protocol: UDP
          - containerPort: 32469
            hostPort: 32469
            protocol: TCP
          - containerPort: 32469
            hostPort: 32469
            protocol: UDP
          - containerPort: 5353
            hostPort: 5353
            protocol: UDP
          - containerPort: 1900
            hostPort: 1900
            protocol: UDP
        env:
        - name: TZ
          value: Europe/London
        - name: PLEX_CLAIM
          value: [REDACTED]
        - name: VERSION
          value: docker
        volumeMounts:
        - mountPath: "/media"
          name: smb
        - mountPath: "/config"
          name: config
        - mountPath: "/transcode"
          name: smb
          subPath: .transcode
        - mountPath: /dev/dri
          name: dri
        securityContext:
          privileged: true
      volumes:
        - name: smb
          persistentVolumeClaim:
            claimName: pvc-plex-smb
        - name: config
          persistentVolumeClaim:
            claimName: plex
        - name: dri
          hostPath:
            path: /dev/dri
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: plex
  name: plex
  namespace: plex 
spec:
  ports:
  - name: web-tcp
    port: 32400
    protocol: TCP
    targetPort: 32400
  selector:
    app: plex
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: plex
  namespace: plex
  annotations: 
    kubernetes.io/ingress.class: traefik-external
    gethomepage.dev/href: "https://plex.f9.casa"
    gethomepage.dev/enabled: "true"
    gethomepage.dev/description: Media Server
    gethomepage.dev/group: Media
    gethomepage.dev/icon: plex.png
    gethomepage.dev/name: Plex
    gethomepage.dev/widget.type: "plex"
    gethomepage.dev/widget.url: "http://plex.plex:32400"
    gethomepage.dev/widget.key: "[REDACTED]"
#    gethomepage.dev/widget.fields: "['movies', 'tv', 'streams']"
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`plex.f9.casa`)
      kind: Rule
      services:
        - name: plex
          port: 32400
      middlewares:
        - name: default-headers
          namespace: default
  tls:
    secretName: f9-casa-tls

Docker Compose

Note that as I use Docker Swarm I am making use of https://github.com/allfro/device-mapping-manager to pass through dev’s to swarm containers by faking a volume, this container then detects that fake volume and maps it as a device

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
version: '3.9'
services:
  plex:
    image: lscr.io/linuxserver/plex:latest
    hostname: plex
   # privileged: true
    networks:
      - traefik-public
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
      - VERSION=docker
    volumes:
      - /srv/cephfs/docker/appdata/plex:/config
      - /srv/media:/media
      - /srv/media/.transcode:/transcode
      - /srv/filmtv:/filmtv
      - /dev/dri:/dev/dri
    ports:
      - 32400:32400
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.plex.rule=Host(`plex.f9.casa`)"
        - "traefik.http.services.plex.loadbalancer.server.port=32400"
        - "traefik.http.routers.plex.entrypoints=websecure"
        - "traefik.http.routers.plex.tls=true"
        - "traefik.http.routers.plex.tls.certresolver=letsencrypt"
        - "traefik.http.services.plex.loadbalancer.healthcheck.path=/identity"
        
        - homepage.group=Media
        - homepage.name=Plex
        - homepage.icon=plex.png
        - homepage.href=https://plex.f9.casa
        - homepage.description=Media server
        - homepage.siteMonitor=http://plex:32400/identity
        - homepage.widget.type=plex
        - homepage.widget.url=http://plex:32400
        - homepage.widget.key=[REDACTED]
        - homepage.widget.fields=["movies", "tv", "streams"]
      mode: replicated
      placement:
        constraints:
          - node.labels.gpu == true
      
networks:
  traefik-public:
    external: true
This post is licensed under CC BY 4.0 by the author.