youtube-dl-server

February 18, 2026 ยท View on GitHub

Docker Stars Shield Docker Pulls Shield GitHub license

youtube-dl-server

Simple Web and REST interface for downloading youtube videos onto a server. starlette + yt-dlp / youtube-dl

Forked from manbearwiz/youtube-dl-server.

screenshot

screenshot

Running

For easier deployment, a docker image is available on dockerhub:

  • nbr23/youtube-dl-server:yt-dlp or simply nbr23/youtube-dl-server to use yt-dlp
  • nbr23/youtube-dl-server:youtube-dl to use youtube-dl. Note that the latest release of youtube-dl is pretty outdated.

Docker CLI

This example uses the docker run command to create the container to run the app. Note the -v argument to specify the volume and its binding on the host. This directory will be used to output the resulting videos.

docker run -d --name youtube-dl -p 8080:8080 -v $HOME/youtube-dl:/youtube-dl nbr23/youtube-dl-server:latest

OR for yt-dlp:

docker run -d --name youtube-dl -p 8080:8080 -v $HOME/youtube-dl:/youtube-dl nbr23/youtube-dl-server:yt-dlp

Docker Compose

This is an example service definition that could be put in docker-compose.yml.

  youtube-dl:
    image: "nbr23/youtube-dl-server:latest"
    volumes:
      - $HOME/youtube-dl:/youtube-dl
      - ./config.yml:/app_config/config.yml:ro # Overwrite the container's config file with your own configuration
    ports:
      - 8080:8080
    restart: always

Configuration

Configuration is done through the config.yml file at the root of the project.

An alternate configuration path or file path can be forced by setting the environment variable YDL_CONFIG_PATH:

export YDL_CONFIG_PATH=/var/local/youtube-dl-server/config.yml

In the above case, if /var/local/youtube-dl-server/config.yml does not exist, it will be created with the default options.

export YDL_CONFIG_PATH=/var/local/youtube-dl-server/

In the above case, if /var/local/youtube-dl-server/config.yml does not exist, it will be created with the default options as well.

ydl_server options

KeyDefaultDescription
port8080Port to listen on
host0.0.0.0IP to bind to
metadata_db_path/youtube-dl/.ydl-metadata.dbPath to the SQLite job database
output_playlist/youtube-dl/%(playlist_title)s [%(playlist_id)s]/%(title)s.%(ext)sOutput template for playlists and multi-URL jobs
max_log_entries100Maximum number of job history entries to keep
default_formatvideo/bestDefault format pre-selected in the UI
download_workers_count2Number of parallel download worker threads
forwarded_allow_ipsNoneComma-separated list of IPs to trust proxy headers from (passed to uvicorn)
proxy_headersTrueTrust X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port headers (passed to uvicorn)
debugFalseEnable debug mode

Minimum required configuration:

ydl_server:
  port: 8080
  host: 0.0.0.0
  metadata_db_path: '/youtube-dl/.ydl-metadata.db'

ydl_options:
  output: '/youtube-dl/%(title)s [%(id)s].%(ext)s'
  cache-dir: '/youtube-dl/.cache'

ydl_options

Additional yt-dlp/youtube-dl parameters can be set in the ydl_options section. Add parameters by removing the leading -- from the flag name.

For example, to write subtitles in spanish, the yt-dlp command would be:

yt-dlp --write-sub --sub-lang es URL

Which translates to:

ydl_options:
  output: '/youtube-dl/%(title)s [%(id)s].%(ext)s'
  cache-dir: '/youtube-dl/.cache'
  write-sub: True
  sub-lang: es

Profiles

Profiles are named configuration sets selectable in the UI. Each profile can override any ydl_options.

profiles:
  podcast:
      name: 'Audio Podcasts'
      ydl_options:
        output: '/youtube-dl/Podcast/%(title)s [%(id)s].%(ext)s'
        format: bestaudio/best
        write-thumbnail: True
        embed-thumbnail: True
        add-metadata: True
        audio-quality: 0
        extract-audio: True
        audio-format: mp3
  philosophy_lectures:
      name: 'Philosophy Lectures'
      ydl_options:
        output: '/youtube-dl/Lectures/Philosophy/%(title)s [%(id)s].%(ext)s'
        write-thumbnail: True
        embed-thumbnail: True
        add-metadata: True
        verbose: True

screenshot

Python

Requires Python ^3.8.

Install dependencies:

pip install -r requirements.txt

Build the frontend:

cd front && npm install && npm run build

Run the server:

python3 -u ./youtube-dl-server.py

To force a specific yt-dlp/youtube-dl fork, set the YOUTUBE_DL environment variable:

YOUTUBE_DL=yt-dlp python3 -u ./youtube-dl-server.py

The following environment variables are used for version display in the UI:

VariableDescription
YOUTUBE_DLThe yt-dlp/youtube-dl module to use (yt-dlp, youtube-dl)
YDLS_VERSIONVersion string shown in the server info endpoint
YDLS_RELEASE_DATERelease date string shown in the server info endpoint

Usage

Web UI

Navigate to http://{{host}}:8080/ and enter the URL to download.

REST API

Queue a download

curl -X POST \
  -H 'Content-Type: application/json' \
  --data-raw '{"url": "{{URL}}", "format": "video/best"}' \
  http://{{host}}:8080/api/downloads

Accepted body fields:

FieldTypeDescription
urlstringSingle URL to download
urlsarrayMultiple URLs to download as one job
formatstringFormat string (see formats below)
profilestringProfile name from config
audio_formatstringAudio format (e.g. mp3, aac)
force_generic_extractorboolForce use of the generic extractor
extra_paramsobjectExtra parameters; title key overrides the output filename

Available format values:

ValueDescription
video/bestBest video+audio (default)
video/bestvideoBest video quality
video/mp4MP4
video/webmWebM
video/mkvMatroska
video/aviAVI
video/flvFlash Video
video/oggOgg
bestaudio/bestBest audio
audio/mp3MP3
audio/aacAAC
audio/flacFLAC
audio/m4aM4A
audio/opusOpus
audio/vorbisVorbis
audio/wavWAV

List jobs

curl http://{{host}}:8080/api/downloads

Query parameters:

ParameterDescription
statusFilter by status: Running, Completed, Failed, Pending, Aborted
show_logsInclude log output in response, 1 (default) or 0

Queue statistics

curl http://{{host}}:8080/api/downloads/stats

Clean old job entries

Removes completed and failed entries beyond max_log_entries:

curl -X POST http://{{host}}:8080/api/downloads/clean

Purge all job history

curl -X DELETE http://{{host}}:8080/api/downloads

Fetch metadata without downloading

curl -X POST \
  -H 'Content-Type: application/json' \
  --data-raw '{"url": "{{URL}}"}' \
  http://{{host}}:8080/api/metadata

Stop a job

curl -X POST http://{{host}}:8080/api/jobs/{{job_id}}/stop

Retry a job

curl -X POST http://{{host}}:8080/api/jobs/{{job_id}}/retry

Delete a job entry

curl -X DELETE http://{{host}}:8080/api/jobs/{{job_id}}

List downloaded files

curl http://{{host}}:8080/api/finished

Delete a downloaded file

curl -X DELETE http://{{host}}:8080/api/finished/{{filename}}

Server info

curl http://{{host}}:8080/api/info

Available formats

curl http://{{host}}:8080/api/formats

Supported extractors

curl http://{{host}}:8080/api/extractors

Bookmarklet

Add the following bookmarklet to your bookmark bar to send the current page URL to your youtube-dl-server instance.

HTTPS

If your youtube-dl-server is served through HTTPS (behind a reverse proxy handling HTTPS for example), you can use the following bookmarklet:

javascript:fetch("https://${host}/api/downloads",{body:JSON.stringify({url:window.location.href,format:"video/best"}),method:"POST",headers:{'Content-Type':'application/json'}});

Plain HTTP

If you are hosting it without HTTPS, the previous bookmarklet will likely be blocked by your browser (mixed content when used on HTTPS sites).

Instead, you can use the following bookmarklet:

javascript:(function(){document.body.innerHTML += '<form name="ydl_form" method="POST" action="http://${host}/api/downloads"><input name="url" type="url" value="'+window.location.href+'"/></form>';document.ydl_form.submit()})();

Notes

Extra format support

ffmpeg is required for format conversion and audio extraction in some scenarios.

Additional references