Last active
January 24, 2025 02:00
-
-
Save jamietre/d463f0f9132f564bf1d7727257eabf13 to your computer and use it in GitHub Desktop.
Script to start WSL and bind localhost to WSL IP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example docker-compose.yml for plex. | |
version: "2" | |
services: | |
plex: | |
image: plexinc/pms-docker:plexpass | |
runtime: nvidia | |
container_name: "plex" | |
restart: always | |
hostname: "MY-PLEX" | |
volumes: | |
- plex-transcode:/transcode | |
- /plex:/config | |
- plex-video:/data/video | |
- plex-music:/data/music | |
ports: | |
- "0.0.0.0:32400:32400" | |
- "0.0.0.0:33400:33400" | |
- "0.0.0.0:65001:65001" | |
environment: | |
TZ: America/New_York | |
PLEX_CLAIM: <your-claim> | |
ADVERTISE_IP: https://your.plex.server | |
PLEX_UID: 1001 | |
PLEX_GID: 1001 | |
NVIDIA_VISIBLE_DEVICES: all | |
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility | |
volumes: | |
# Examples only | |
plex-music: | |
driver: local | |
driver_opts: | |
type: cifs | |
device: //192.168.1.2/media/MusicLibrary | |
o: "username=plex,password=xxxx" | |
plex-video: | |
driver: local | |
driver_opts: | |
type: cifs | |
device: //192.168.1.2/media/VideoLibrary | |
o: "username=plex,password=xxxx" | |
plex-transcode: | |
external: false | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
service docker start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"C:\Program Files\nodejs\node.exe" "c:\scripts\configure-wsl-plex.js" >> "c:\scripts\configure-wsl-plex.log" 2>&1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { exec } = require("child_process"); | |
const distro = "Ubuntu-20.04"; | |
const ipPattern = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/; | |
async function main() { | |
log("info", "Starting WSL initialization"); | |
const isRunning = await isWslDistroRunning(); | |
if (!isRunning) { | |
log("info", "Distro stopped, starting..."); | |
await runCommand(`wsl -d ${distro} -u root /etc/init-wsl`); | |
} | |
const data = await runCommand("C:\\Windows\\System32\\wsl.exe hostname -I"); | |
const parts = data.split(" "); | |
const ip = parts[0]; | |
if (!ipPattern.test(ip)) { | |
throw new Error(`Received '${data}'; could not extract an IP`); | |
} | |
log("info", `Configuring netsh to route to ${ip}`); | |
try { | |
await runCommand( | |
'netsh interface portproxy delete v4tov4 listenaddress="0.0.0.0" listenport=32400' | |
); | |
} catch (e) { | |
log("warn", e.message) | |
} | |
await runCommand( | |
`netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=32400 connectaddress=${ip} connectport=32400` | |
); | |
log("info", "Done"); | |
} | |
async function isWslDistroRunning() { | |
const distroText = distro.replace(/\./g, "\\."); | |
const wslStatePattern = new RegExp( | |
`\\*?\\s*${distroText}\\s*(Running|Stopped)\\s*(1|2)` | |
); | |
const wslState = await runCommand("wsl --list --verbose"); | |
const lines = splitLines(wslState); | |
const distroMatches = lines.filter((line) => wslStatePattern.test(line)); | |
if (distroMatches.length > 1) { | |
throw new Error( | |
`More than one match for distro name "${distro}" was found, can't continue.` | |
); | |
} | |
if (distroMatches.length === 0) { | |
throw new Error(`No matches for distro name "${distro}".`); | |
} | |
const matches = distroMatches[0].match(wslStatePattern); | |
const state = matches[1]; | |
log("info",`Machine state: ${state}`) | |
switch (state) { | |
case "Running": | |
return true; | |
case "Stopped": | |
return false; | |
default: | |
throw new Error(`Unknown wsl state "${state}"`); | |
} | |
} | |
async function runCommand(command) { | |
const deferred = createDeferred(); | |
log("info", `> ${command}`); | |
exec(command, function (err, stdout, stderr) { | |
if (err) { | |
deferred.reject(err); | |
return; | |
} | |
if (stderr) { | |
log("error", stderr); | |
} | |
deferred.resolve(stdout); | |
return; | |
}); | |
return deferred.promise(); | |
} | |
/** | |
* make a promise, and provide the resolve/reject functions | |
*/ | |
function createDeferred() { | |
let resolve; | |
let reject; | |
const promise = new Promise((_resolve, _reject) => { | |
resolve = _resolve; | |
reject = _reject; | |
}); | |
return { | |
promise: async () => promise, | |
resolve: resolve, | |
reject: reject, | |
}; | |
} | |
function splitLines(lines) { | |
let cleanLines = lines.replace(/\r/g, "").replace(/\0/g, ""); | |
while (cleanLines.endsWith("\n")) { | |
cleanLines = cleanLines.slice(0, cleanLines.length - 1); | |
} | |
return cleanLines.split("\n"); | |
} | |
function log(level, message) { | |
const now = new Date().toISOString(); | |
console.log(`${now} [${level}] ${message}`); | |
} | |
main() | |
.then(() => { | |
process.exit(0); | |
}) | |
.catch((e) => { | |
log("error", e.message); | |
process.exit(1); | |
}); |
You are a genius!
Docker Desktop now supports remote WSL2 containers - I think you now only need the compose file and the rest can be achieved natively there.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Plex, Docker, WSL2, hardware transcoding
Since WSL2 supports GPU access -- in latest Windows 10 feature update and Windows 11 - it is actually somewhat reasonable/performant to run Plex in docker in WSL. I want to do this because it's much easier to manage/maintain dockerized plex than the Windows installation; it's also easily portable to another linux box if want to move it. But I want to use my GPU for other things in Windows at the same time so I don't want to dedicate this box to running linux.
Lo and behold, since the latest Windows feature update, it actually works, and I get hardware transcoding running plex in WSL2 in windows! But WSL2 isn't really ready to act as a reliable server foundation out of the box:
This script solves these problems.
How to get it working
This gist includes a javascript program to check if WSL is running; start it if not; start docker; and to map localhost to the current WSL IP for plex web port so that the world can access your plex server.
I've included an example docker-compose.yml, but this is not really specific to this problem. There are lots of great guides for running plex in Docker generally.
This assumes you're using an Ubuntu distro; may vary for others.
/etc/init-wsl
chmod +x /etc/init-wsl
c:\scripts\start-wsl.cmd
Using Nvidia GPU in WSL2
The instructions provided by Nvidia pretty much work out of the box. One thing that tripped me up and is not really obvious from anything I read online is that you cannot use Docker Desktop on windows at the same time. Docker desktop does not (yet?) support the nvidia runtime. Uninstall docker desktop, and follow the Docker CE installation instructions in the nvidia guide below. Ignore the warnings when installing it about "you should use docker desktop."
Nvidia GPU access in WSL
Nvidia CUDA WSL setup