Skip to content

Instantly share code, notes, and snippets.

@jamietre
Last active June 11, 2024 12:14
Show Gist options
  • Save jamietre/d463f0f9132f564bf1d7727257eabf13 to your computer and use it in GitHub Desktop.
Save jamietre/d463f0f9132f564bf1d7727257eabf13 to your computer and use it in GitHub Desktop.
Script to start WSL and bind localhost to WSL IP
# 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
#!/bin/sh
service docker start
"C:\Program Files\nodejs\node.exe" "c:\scripts\configure-wsl-plex.js" >> "c:\scripts\configure-wsl-plex.log" 2>&1
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);
});
@mikaelweave
Copy link

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