Proxmox-for-Channels: Step-by-Step for Creating a Chrome-Capture-for-Channels (cc4c) LXC Container

EDIT (10 April 25): I've reworked this post to reflect my latest recommendations for creating a cc4c LXC container in Proxmox. This now uses a Debian 12 template and incorporates the @dravenst cc4c repo. This repo features better error handling, more descriptive console output, command line switches for configurable elements, and some specific support for Sling. I've also added suggested changes to ~/.bashrc to run cc4c on login in an additional post.

I've tried, as have others, to get the Docker version of Chrome-Capture-for-Channels working better. Although, a few have reported acceptable results, most have not. Being able to containerize it, has appeal though -- so, I thought I'd take a shot at installing cc4c directly in a Proxmox LXC container.

It appears to work well, so I thought I'd document the steps for creating a cc4c LXC here:

Stepping through the usual series of windows for creating a new LXC, here are the values I used:

Debian 12 (Bookworm) is the choice here:

8GB should be adequate for disk space, though 16GB is nice if you have the space available:

Cores are important here, with 6 being a nice generous number if you have the vCPUs (which are OK to over allocate). 4 would probably be fine too -- below that I wouldn't recommend:

4096 is generous, 2048 should be fine too. Keep in mind you're running Chrome:

vmbr1 is my 10GbE bridge, so I'm using that. No firewall, and DHCP on IPv4, but use whatever is typical for you:

I'm passing through my iGPU (which can be shared with other LXCs), using the Proxmox 8 method:

And then, here's what needs to be done from the new LXC's Console. These steps are essentially duplicating what's done in the cc4c Dockerfile:

# Add the non-free and non-free-firmware repos to sources.list
sed -i 's/contrib$/contrib non-free non-free-firmware/' /etc/apt/sources.list

# Add va drivers
apt update

apt install intel-media-va-driver-non-free vainfo libva-drm2 libva-x11-2 mesa-va-drivers

# Upgrade the container's OS
apt upgrade

# Install some basic system packages
apt install curl gnupg git

# Add the Node 18 repo via script and install nodejs
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -

apt install nodejs

# Install needed system libraries and utilities
apt install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable x11-apps xvfb xserver-xorg-core x11-xserver-utils xauth

# Add the Chrome signing key and install Chrome
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -

echo "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list

apt update

apt install google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 --no-install-recommends

# Clone the cc4c repo and install it
cd /opt

git clone https://github.com/dravenst/chrome-capture-for-channels

cd chrome-capture-for-channels

npm install # There will be some warnings here about vulnerabilities that can be safely ignored

# Add required environment variables needed by cc4c and Chrome
echo -e "DISPLAY=:99\nCHROME_BIN=/usr/bin/google-chrome\nDOCKER=true\nLIBGL_ALWAYS_INDIRECT=1\nLIBVA_DRIVER_NAME=iHD" | tee /etc/environment > /dev/null

# Exit followed by a fresh login to pick up the new env vars
exit

At this point you'll be logged out of the LXC's Console, so log back in, and switch to the /opt/chrome-capture-for-channels directory:

cd /opt/chrome-capture-for-channels

The last step will run Xvbf, a VNC server and cc4c itself:

Xvfb :99 -screen 0 1920x1080x16 & x11vnc -quiet -nopw -display :99 -forever & node main.js

cc4c is now running in the foreground, with the other two running in the background, and you should see something like this on your Console:

[1] 16268
[2] 16269
Xlib:  extension "DPMS" missing on display ":99".

The VNC desktop is:      cc4c2:0
PORT=5900
[2025/02/08 09:09:32.750] Chrome Capture server listening on port 5589

If you kill the foreground cc4c process for any reason. Be sure to kill the two background processes as well. Their PIDs are shown as [1] and [2] at this stage, or you can get them with a ps -ef command.

When you setup your CDVR Custom Channels Source, be sure to include chrome://gpu as a channel so you can check Chrome's stats regarding GPU use:

#EXTM3U

#EXTINF:-1 channel-id="weatherscan",Weatherscan
chrome://cc4c:5589/stream?url=https://v2.weatherscan.net/

#EXTINF:-1 channel-id="chrome.gpu",Chrome GPU
chrome://cc4c:5589/stream?url=chrome://gpu

Use the cc4c hostname in the above M3U if it resolves on your LAN, or substitute the IP address of the LXC container.

Use a VNC client to connect to the container, when a cc4c stream is active, if you need to login to a streaming service, or to go fullscreen. Logins and fullscreen player settings should be maintained by Chrome just like when you're using Chrome locally.

I'll add a script that'll autorun at container start, once I put this into production, and I'll update this step-by-step accordingly.

2 Likes

As usual, your contributions are greatly appreciated!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

Here are my recommended additions to ~/.bashrc to run cc4c at login with whatever command line switches you'd like to use:

# Usage: node main.js [options]
#
# Options:
#   -v, --videoBitrate  Video bitrate in bits per second  [number] [default: 6000000]
#   -a, --audioBitrate  Audio bitrate in bits per second  [number] [default: 256000]
#   -f, --frameRate     Minimum frame rate  [number] [default: 30]
#   -p, --port          Port number for the server  [number] [default: 5589]
#   -w, --width         Video width in pixels (e.g., 1920 for 1080p)  [number] [default: 1920]
#   -h, --height        Video height in pixels (e.g., 1080 for 1080p)  [number] [default: 1080]
#   -i, --videoCodec    Video codec (e.g., h264_nvenc, h264_qsv, h264_amf, h264_vaapi)  [string] [default: "h264_nvenc"]
#   -u, --audioCodec    Audio codec (e.g., aac, opus)  [string] [default: "aac"]
#   -?, --help          Show help  [boolean]
#
# Examples:
#   node main.js -v 6000000 -a 192000 -f 30 -w 1920 -h 1080
#   node main.js --videoBitrate 8000000 --frameRate 60 --width 1920 --height 1080

cd /opt/chrome-capture-for-channels
Xvfb :99 -screen 0 1920x1080x16 & x11vnc -quiet -nopw -display :99 -forever & node main.js -v 8500000 -f 60

Put the whole block in there, including the commented out lines, in case you want to modify any of the command line switches in the future.

Here's a sample of what you'd see when logging in using this approach, including one channel tune:

Linux cc4c 6.8.12-2-pve #1 SMP PREEMPT_DYNAMIC PMX 6.8.12-2 (2024-09-05T10:03Z) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Apr 10 16:16:52 UTC 2025 on tty1
Xlib:  extension "DPMS" missing on display ":99".

The VNC desktop is:      cc4c:0
PORT=5900
[2025/04/10 16:18:09.869] Selected settings:
[2025/04/10 16:18:09.870] Video Bitrate: 8500000 bps (8.5Mbps)
[2025/04/10 16:18:09.870] Audio Bitrate: 256000 bps (256kbps)
[2025/04/10 16:18:09.870] Minimum Frame Rate: 60 fps
[2025/04/10 16:18:09.870] Port: 5589
[2025/04/10 16:18:09.870] Resolution: 1920x1080
[2025/04/10 16:18:09.870] Video Codec: h264_nvenc
[2025/04/10 16:18:09.870] Audio Codec: aac
[2025/04/10 16:18:09.874] Chrome Capture server listening on port 5589
[2025/04/10 16:22:04.313] Launching Browser, Opts {
  executablePath: '/usr/bin/google-chrome',
  pipe: true,
  headless: false,
  defaultViewport: null,
  userDataDir: '/opt/chrome-capture-for-channels/chromedata',
  args: [
    '--no-first-run',
    '--hide-crash-restore-bubble',
    '--allow-running-insecure-content',
    '--autoplay-policy=no-user-gesture-required',
    '--disable-blink-features=AutomationControlled',
    '--hide-scrollbars',
    '--window-size=1920,1080',
    '--disable-notifications',
    '--disable-background-networking',
    '--disable-background-timer-throttling',
    '--disable-background-media-suspend',
    '--disable-backgrounding-occluded-windows',
    '--load-extension=/opt/chrome-capture-for-channels/node_modules/puppeteer-stream/extension',
    '--disable-extensions-except=/opt/chrome-capture-for-channels/node_modules/puppeteer-stream/extension',
    '--allowlisted-extension-id=jjndjgheafjngoipoacpjgeicjeomjli',
    '--auto-accept-this-tab-capture',
    '--use-gl=angle',
    '--use-angle=gl-egl',
    '--enable-features=VaapiVideoDecoder,VaapiVideoEncoder',
    '--ignore-gpu-blocklist',
    '--enable-zero-copy',
    '--enable-drdc',
    '--no-sandbox'
  ],
  ignoreDefaultArgs: [
    '--enable-automation',
    '--disable-extensions',
    '--disable-default-apps',
    '--disable-component-update',
    '--disable-component-extensions-with-background-pages',
    '--enable-blink-features=IdleDetection'
  ],
  extensionPath: '/opt/chrome-capture-for-channels/node_modules/puppeteer-stream/extension'
}
[2025/04/10 16:22:04.676] New target page created: about:blank
[2025/04/10 16:22:04.699] Target page changed: chrome-extension://jjndjgheafjngoipoacpjgeicjeomjli/options.html#55200
[2025/04/10 16:22:05.690] Need to initialize stream capabilities
[2025/04/10 16:22:05.759] streaming https://watch.sling.com/1/channel/d96b102ac5c54967bf56b8b57e20c84e/watch
[2025/04/10 16:22:05.936] Target page changed: https://watch.sling.com/1/channel/d96b102ac5c54967bf56b8b57e20c84e/watch
[2025/04/10 16:22:05.954] URL contains watch.sling.com
[2025/04/10 16:22:08.140] New target page created: blob:https://watch.sling.com/f479666f-6ca1-4602-b020-edf65675ca88
[2025/04/10 16:22:08.215] Browser page closed: blob:https://watch.sling.com/f479666f-6ca1-4602-b020-edf65675ca88
[2025/04/10 16:22:11.057] Set Sling to Full Screen and Volume to max

Use the console anytime you want to see what's happening with cc4c. Use WinSCP and/or putty if you need to make a second connection via ssh. Use a VNC client to connect to the container for entering streaming credentials, or for any other interaction with Chrome.

Just in case this helps with anyone else, I updated the resolution in both main.js and the x session to 720p on my humble proxmox server and it really smoothed out playback (at the expense of picture quality obviously). Not quite perfect but definitely watchable.