Workflow guide
How to run yt-dlp on a server
yt-dlp on your laptop and yt-dlp on a VPS are different animals. Servers have no browser for cookies, their IP ranges are aggressively blocked by major sites, and nobody notices when a silent extractor breakage stops your downloads for a week. Here is what actually changes.
Headless install
# Debian/Ubuntu server
sudo apt install ffmpeg
python3 -m pip install -U yt-dlp
# or the standalone binary (no Python needed)
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
chmod a+rx /usr/local/bin/yt-dlpffmpeg is not optional: without it, merging video+audio formats and most conversions fail. If downloads work locally but fail on the server, check ffmpeg first.
Docker setup
There is no official yt-dlp image. A minimal Dockerfile you control beats a third-party image of unknown freshness — and freshness matters more for yt-dlp than for almost any other tool:
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -U yt-dlp
WORKDIR /downloads
ENTRYPOINT ["yt-dlp"]docker build -t yt-dlp .
docker run --rm -v "$PWD:/downloads" yt-dlp "URL"Rebuild the image on a schedule (weekly is reasonable) so the baked-in yt-dlp doesn't rot. A pinned, months-old yt-dlp is the most common cause of "it worked when I set it up."
The real problem: datacenter IP blocks
YouTube and other large platforms treat AWS, GCP, Hetzner, and most VPS ranges as bot traffic. Symptoms: HTTP 403, "Sign in to confirm you're not a bot", heavy throttling, or downloads that work for a day and then stop. This is not a yt-dlp bug and updating won't fix it — your IP reputation is the problem.
- •
--proxythrough residential or ISP proxies helps, at real per-GB cost and added flakiness - • cookies from a logged-in account help, but risk that account being flagged — never use one you care about
- • serverless (Lambda, Cloud Functions) is the worst case: shared IP pools that other people already burned, plus ffmpeg packaging pain and execution time limits
- • spacing out requests with
--sleep-requestsand limiting concurrency extends how long an IP stays usable
Cookies without a browser
--cookies-from-browser does not work on a headless box — there is no browser. Export a cookies.txt from your local machine and ship it to the server:
yt-dlp --cookies /etc/yt-dlp/cookies.txt "URL"Cookies expire and get invalidated when the site sees suspicious usage, so treat them as a consumable you rotate — not a set-and-forget config. Details in the cookies guide.
Keep it updated or it will break
Sites change their internals constantly; yt-dlp ships fixes constantly. A server install that nobody updates is a countdown timer. Automate it:
# cron: update Sunday 4am, log the result
0 4 * * 0 /usr/local/bin/yt-dlp -U >> /var/log/yt-dlp-update.log 2>&1
# pip installs update with pip instead
0 4 * * 0 python3 -m pip install -U yt-dlp >> /var/log/yt-dlp-update.log 2>&1Also alert on failures: a download job that exits non-zero should page you or post to Slack, because the default failure mode is silence. See updating yt-dlp for version pinning trade-offs.
Common server mistakes
- • assuming laptop behavior transfers — the IP reputation is completely different
- • baking yt-dlp into an image once and never rebuilding
- • running as root with downloads landing wherever the cwd happens to be
- • no disk-space management — video files fill a small VPS fast
- • using a personal account's cookies for automation
- • no alerting, so breakage is discovered weeks later
If it keeps breaking
Tired of fixing this every time a site changes?
Paste a link to see what a managed import API returns — the one that stays current so your workflow doesn't break.