{"id":19712148,"url":"https://github.com/fmstrat/plex-cluster","last_synced_at":"2026-02-26T12:04:51.467Z","repository":{"id":42237745,"uuid":"262047449","full_name":"Fmstrat/plex-cluster","owner":"Fmstrat","description":"Synchronizes the watched and timeline status between any number of Plex servers all using standard Plex APIs.","archived":false,"fork":false,"pushed_at":"2023-01-24T05:05:55.000Z","size":216,"stargazers_count":53,"open_issues_count":15,"forks_count":9,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-10-28T02:23:54.812Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Fmstrat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-07T12:43:37.000Z","updated_at":"2024-10-03T00:50:56.000Z","dependencies_parsed_at":"2023-01-28T16:16:35.959Z","dependency_job_id":null,"html_url":"https://github.com/Fmstrat/plex-cluster","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Fmstrat/plex-cluster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fmstrat%2Fplex-cluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fmstrat%2Fplex-cluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fmstrat%2Fplex-cluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fmstrat%2Fplex-cluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Fmstrat","download_url":"https://codeload.github.com/Fmstrat/plex-cluster/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fmstrat%2Fplex-cluster/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29858461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T22:15:28.049Z","updated_at":"2026-02-26T12:04:51.433Z","avatar_url":"https://github.com/Fmstrat.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Plex Cluster\nSynchronizes the watched and timeline status between any number of Plex servers all using standard Plex APIs.\n\n***This project is in BETA TESTING.***\n\nPlex Cluster contains two applications:\n- **Plex Cluster Proxy**, which is installed alongside every Plex server and acts as a proxy (using `nginx`) between Plex Media Server and the internet. This application's job is to pass any requests that come to it along to the Plex server while catching any requests that mark watched status and also forwarding them on the **Plex Cluster Manager**. There is one instance of `Plex Cluster Proxy` for each Plex server.\n- **Plex Cluster Manager** is then used to synchronize the status between Plex servers. There is only one instance of `Plex Cluster Manager` which is used by all instances of `Plex Cluster Proxy`.\n\nAn example use case:\n1. Plex client requests to watch a show with GIUD (unique identifier) `ABC` from the `TV Shows` library on `Plex Server 1`\n2. The request goes through `Plex Cluster Proxy 1` and is passed along to `Plex Server 1`\n3. The user stops the show midway.\n4. The request goes through `Plex Cluster Proxy 1` and is passed along to `Plex Server 1`, but is also passed along to `Plex Cluster Manager`\n5. `Plex Cluster Manager` takes the request and checks for any other Plex server with a library named `TV Shows` and GUID `ABC`\n6. For any other servers it finds, such as `Plex Server 2`, it forwards the request on to them and the show is instantly marked as watched up to that midway point.\n7. User switches over to `Plex Server 2` and sees that they are midway through show `ABC`\n\n## Features\n- Syncs watched status on-demand, right away\n- Uses standard Plex APIs without accessing the database\n- Can work across multiple Plex servers\n- Scheduled \"full update\" can completely sync user's watched status for any user that has been active on each Plex server since running `Plex Cluster`\n- Syncs media that is contained on both (or multiple) servers without erroring when media does not exist\n- Works for Plex.tv or Managed users\n\n## To Do\n- Support \"full sync\" for users on some Roku models and other devices that encapsulate a temporary token in the request header (this does not impact on-demand sync)\n\n## Requirements\n- Each Plex server must have a dedicated DNS or Dynamic DNS hostname\n\n## Installation\nThe best way to use `Plex Cluster` is with Docker. You can follow the `Dockerfile`s to set up the proxy manually, however if you're not running Docker for your services, you're missing out.\n\nThis installation follows this example:\n- 2 Plex servers, one at home called `Home` and one remote called `Remote`\n- `Home` has...\n    - a public DNS record of `plex-home.mydomain.com`\n    - a Plex server running on `192.168.0.10:32400`\n    - a Plex Cluster Proxy instance running on `https://plex-home.mydomain.com:32401`\n    - a wildcard SSL certificate for `*.mydomain.com` in the `/certs` folder\n- `Remote` has...\n    - a public DNS record of `plex-remote.mydomain.com`\n    - a Plex server running on `192.168.1.10:32400`\n    - a Plex Cluster Proxy instance running on `https://plex-remote.mydomain.com:32401`\n    - a Plex Cluster Manager instance running on `https://plex-remote.mydomain.com:32402`\n    - a wildcard SSL certificate for `*.mydomain.com` in the `/certs` folder\n\n### Setting up the Home instance\nFirst, we need a Plex server, and a copy of `Plex Cluster Proxy` running at home. These can be spun up with the following `docker-compose.yml`:\n\n``` yml\nversion: '3.7'\n\nservices:\n\n  # A proxy based on nginx that sits between the Plex server and\n  # the internet. Every time a request is made to Plex, if that\n  # request is to mark status, an API call is made\n  # to plex-cluster-manager.\n  #\n  # There is one of these for every Plex server.\n  plex-cluster-proxy:\n    image: nowsci/plex-cluster-proxy\n    container_name: plex-cluster-proxy\n    environment:\n      - PLEX_IP=192.168.0.10 # The IP address of the Plex server's NIC\n      - PLEX_PORT=32400      # The port Plex is listening on\n      - HTTPS_HOST=plex-home.mydomain.com # The host that Plex Cluster Proxy will listen on\n      - HTTPS_PORT=32401                  # The port that Plex Cluster Proxy will listen on\n      - RESOLVERS=8.8.4.4 8.8.8.8 # DNS servers that Plex Cluster Proxy should use\n      - SSL_CERTIFICATE=/certs/fullchain.pem   # Mapped location of the below SSL cert\n      - SSL_CERTIFICATE_KEY=/certs/privkey.pem # Mapped location of the below SSL cert\n      - CLUSTER_MANAGER=https://plex-remote.mydomain.com:32402 # URL of Plex Cluster Manager\n      - CLUSTER_MANAGER_TOKEN=JgUNaJ6DcB7FhhYGcUpaa9DwPy       # CHANGE THIS: A random token that Plex Cluster Proxy will use to authenticate with Manager\n    volumes:\n      - /etc/localtime:/etc/localtime:ro # Keeps time in sync\n      - ./certs/fullchain.pem:/certs/fullchain.pem:ro # Mapped path to the SSL certificate\n      - ./certs/privkey.pem:/certs/privkey.pem:ro     # Mapped path to the SSL certificate\n      - plex-cluster-proxy:/data # Docker volume where log data is stored for processing\n    ports:\n      - 32401:32401 # Port mapping (same as HTTPS_PORT), forward this port on your firewall\n    restart: always # Restart on failure\n\n  # The Home Plex server\n  # This assumes you have Plex Pass\n  plex:\n    image: plexinc/pms-docker:plexpass\n    container_name: plex\n    environment:\n      - TZ=America/New_York\n    network_mode: bridge\n    ports:\n      - \"192.168.0.10:32400:32400/tcp\" # The port and IP to listen on, do not forward this port on your firewall\n    volumes:\n      - ./plex/plex/config:/config # Where you want your Plex Library/Config folder to be\n      - /storage/transcode/plex:/transcode # A path for transcoding\n      - /storage/transcode/plex/Sync+:/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sync+ # To keep sync transcoding in the transcode folder\n      - /storage/transcode/plex/Sync:/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sync   # To keep sync transcoding in the transcode folder\n      - /storage/media:/media # Media folder\n    restart: always\n\nvolumes:\n  plex-cluster-proxy:    \n```\n\nAfter you spin this up with `docker-compose up -d`, navigate in your browser to `http://192.168.0.10:32400/web` and login to your new server. A few key things to set up are:\n- Settings -\u003e Remote Access -\u003e Disable Remote Access (Don't worry, you'll still be able to get here through your custom URL)\n- Settings -\u003e Network -\u003e Click Show Advanced\n- Settings -\u003e Network -\u003e Secure connections -\u003e Choose `Required`\n- Settings -\u003e Network -\u003e Custom server access URLs -\u003e Enter `https://plex-home.mydomain.com:32401`\n\nThe home server setup is complete.\n\n### Setting up the Remote instance\nNext we need a Plex server, a copy of `Plex Cluster Proxy` and a copy of `Plex Cluster Manager` running remotely. These can be spun up with the following `docker-compose.yml`:\n\n``` yml\nversion: '3.7'\n\nservices:\n\n  # A proxy based on nginx that sits between the Plex server and\n  # the internet. Every time a request is made to Plex, if that\n  # request is to mark status, an API call is made\n  # to plex-cluster-manager.\n  #\n  # There is one of these for every Plex server.\n  plex-cluster-proxy:\n    image: nowsci/plex-cluster-proxy\n    container_name: plex-cluster-proxy\n    environment:\n      - PLEX_IP=192.168.1.10 # The IP address of the Plex server's NIC\n      - PLEX_PORT=32400      # The port Plex is listening on\n      - HTTPS_HOST=plex-remote.mydomain.com # The host that Plex Cluster Proxy will listen on\n      - HTTPS_PORT=32401                    # The port that Plex Cluster Proxy will listen on\n      - RESOLVERS=8.8.4.4 8.8.8.8 # DNS servers that Plex Cluster Proxy should use\n      - SSL_CERTIFICATE=/certs/fullchain.pem   # Mapped location of the below SSL cert\n      - SSL_CERTIFICATE_KEY=/certs/privkey.pem # Mapped location of the below SSL cert\n      - CLUSTER_MANAGER=http://plex-cluster-manager:32402 # URL of Plex Cluster Manager (local Docker URL in this case)\n      - CLUSTER_MANAGER_TOKEN=JgUNaJ6DcB7FhhYGcUpaa9DwPy  # CHANGE THIS: A random token that Plex Cluster Proxy will use to authenticate with Manager\n    volumes:\n      - /etc/localtime:/etc/localtime:ro # Keeps time in sync\n      - ./certs/fullchain.pem:/certs/fullchain.pem:ro # Mapped path to the SSL certificate\n      - ./certs/privkey.pem:/certs/privkey.pem:ro     # Mapped path to the SSL certificate\n      - plex-cluster-proxy:/data # Docker volume where log data is stored for processing\n    ports:\n      - 32401:32401 # Port mapping (same as HTTPS_PORT), forward this port on your firewall\n    restart: always # Restart on failure\n\n  # The service that sychronizes the Plex servers. It takes the API calls\n  # from plex-cluster-proxy, and reaches out to any other configured Plex\n  # servers to set their status just as if the client connecting to the\n  # original Plex server was connecting to that one instead.\n  #\n  # You will want to secure this behind an SSL proxy in the real world.\n  #\n  # There is only ever one of these.\n  plex-cluster-manager:\n    image: nowsci/plex-cluster-manager\n    container_name: plex-cluster-manager\n    environment:\n      - CLUSTER_MANAGER_TOKEN=JgUNaJ6DcB7FhhYGcUpaa9DwPy # CHANGE THIS: A random token that Plex Cluster Proxy will use to authenticate with Manager\n      - UPDATE_ON_START=true # Do a full sync on start\n      - DEBUG=false # Output debug logs\n      - FULL_SYNC_SCHEDULE=0 2 * * * # A cron-styled schedule for when to run the full sync\n    volumes:\n      - /etc/localtime:/etc/localtime:ro # Keeps time in sync\n      - ./config/plex-cluster-manager.yml:/config/plex-cluster-manager.yml:ro # A config file, see below\n      - plex-cluster-manager:/data # Where Plex Cluster Manager stores it's SQLite DB\n    restart: always\n\n  # The Remote Plex server\n  # This assumes you have Plex Pass\n  # You could also clone the Home server and remove Preferences.xml before starting\n  plex:\n    image: plexinc/pms-docker:plexpass\n    container_name: plex\n    environment:\n      - TZ=America/New_York\n    network_mode: bridge\n    ports:\n      - \"192.168.1.10:32400:32400/tcp\" # The port and IP to listen on, do not forward this port on your firewall\n    volumes:\n      - ./plex/plex/config:/config # Where you want your Plex Library/Config folder to be\n      - /storage/transcode/plex:/transcode # A path for transcoding\n      - /storage/transcode/plex/Sync+:/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sync+ # To keep sync transcoding in the transcode folder\n      - /storage/transcode/plex/Sync:/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sync   # To keep sync transcoding in the transcode folder\n      - /storage/media:/media # Media folder\n    restart: always\n\nvolumes:\n  plex-cluster-manager:\n  plex-cluster-proxy:    \n```\nBefore starting it up, you will need to create the `plex-cluster-manager.yml` configuration file ([sample](config/plex-cluster-manager.sample.yml)). This file looks like:\n``` yml\nhosts:\n  - host: plex.mydomain.com\n    port: 11111\n    token: xxxxxxxxxxxxxxxxxxxx\n    #log: ./plex.log    # This is not commonly used. It is only used to tail a local log.\n```\nThe token should be a Plex token for the administrative user on the Plex server. You can get a token from Plex using [this script](tools/get-plex-token.sh).\n\nAfter you spin this up with `docker-compose up -d`, navigate in your browser to `http://192.168.1.10:32400/web` and login to your new server. A few key things to set up are:\n- Settings -\u003e Remote Access -\u003e Disable Remote Access (Don't worry, you'll still be able to get here through your custom URL)\n- Settings -\u003e Network -\u003e Click Show Advanced\n- Settings -\u003e Network -\u003e Secure connections -\u003e Choose `Required`\n- Settings -\u003e Network -\u003e Custom server access URLs -\u003e Enter `https://plex-remote.mydomain.com:32401`\n\nThe remote server setup is complete.\n\n### Final steps\n\nOnce everything is complete, login via `https://plex.tv` and if you watch the logs via `docker-compose logs -ft` and mark shows watched you should start seeing `plex-cluster-proxy` and `plex-cluster-manager` synchronize the status.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffmstrat%2Fplex-cluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffmstrat%2Fplex-cluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffmstrat%2Fplex-cluster/lists"}