To run an FFmpeg playlist stream in Docker, make FFmpeg the foreground process of a Compose service, mount the playlist and media into the container, and configure the YouTube ingest URL and stream key. Choose a loop method for the playlist format you actually have; Docker packages the process but does not make incompatible media work or guarantee an uninterrupted broadcast.
The practical pattern is to test the command outside the container first, then give Compose the same command and paths. YouTube Studio provides the destination details, and its Live Control Room is where you check the incoming preview and stream health before relying on the setup.
How the containerised stream works
Docker runs a container from an image, and Docker Compose describes how to start that container and what files or settings it needs. In this arrangement, the container’s main process is FFmpeg. FFmpeg reads a playlist and its media, optionally encodes the audio and video, then sends a live output to YouTube over RTMPS. If FFmpeg exits, the container exits too; a Compose restart policy can ask Docker to start it again, but that is process recovery, not proof that YouTube is receiving a healthy picture and sound.
A container can make the runtime environment and command easier to reproduce. It does not repair a broken playlist path, convert unsupported input formats by magic, provide a YouTube stream key, or remove dependence on a stable network connection. The media still needs to decode, the output still needs to meet YouTube’s ingest expectations, and the machine running Docker still needs to stay available.
This is a good fit if you already know how to operate a Linux host or a machine with Docker and are comfortable checking logs. If you want to compare the operational burden with a managed approach, the considerations in cloud loop streaming versus NGINX RTMP are relevant. A rented VPS is not mandatory: a suitable always-on computer can run Compose too, provided its network and power situation suit your needs.
Before configuring output, confirm the channel can go live. YouTube’s live-streaming eligibility guidance says to check channel verification, age requirements, and any live-streaming restrictions. Account eligibility is separate from whether FFmpeg can connect.
Prepare the playlist and media files
Start with a small, known set of files and a playlist whose format you can identify. For example, an M3U file may contain paths to local media, while a concat-demuxer list uses a different syntax and has different requirements. Do not assume that a playlist made for a desktop player will work unchanged with every FFmpeg input option. Check the FFmpeg documentation for the demuxer and options that match your playlist type, then verify the behaviour with the FFmpeg build you intend to run.
Keep the playlist and referenced media together in a directory on the host, such as ./media. Use clear filenames and avoid changing the directory while the broadcast is running. Paths inside a playlist need to make sense from the process that opens them: a host path such as /home/you/videos/track.mp4 is not automatically available inside a container. When you mount ./media at /media, the container sees that location and playlist entries must resolve there, or be written in a form that resolves relative to the playlist as intended.
Inspect each file before attempting a long run. ffprobe, which is commonly packaged alongside FFmpeg, can show container, video, and audio stream details. A file extension is not enough to establish codec compatibility. Mixed frame rates, missing audio, unusual timestamps, variable frame rates, and different dimensions can all affect whether files can be concatenated or played back as one continuous output. Test transitions, not just the first clip.
Make the container’s media mount read-only if FFmpeg only needs to read source files. This avoids accidental changes from the streaming process and makes the intent clear. If you need to edit the playlist, do it on the host and restart or deliberately reload the process; do not expect all playlist readers to notice edits in the same way.
For a real channel, plan the content as well as the mechanics. A continuous loop can be technically valid without being appropriate for every rights or monetisation situation. YouTube scans live streams for third-party content, and rights holders may have requirements for content they have allowed. Its copyright guidance for live streams is a better source than assuming a file that plays locally is cleared for broadcast. Likewise, a playlist alone does not establish eligibility for monetisation.
Choose a loop strategy
There is no universal loop switch that makes every playlist repeat correctly. The right approach depends on whether FFmpeg is reading one media file, an M3U playlist, a concat list, or a sequence generated by another process. The official FFmpeg options reference documents input looping and playlist-related behaviour, but options apply in context and their placement relative to inputs matters.
For one file, an input loop option may be appropriate; for example, FFmpeg supports -stream_loop -1 to loop an input indefinitely. That example is not a general playlist solution. Applied to a playlist demuxer, it may loop the playlist input as a unit, but you must check what that demuxer supports and whether the transitions and timestamps remain acceptable. For a concat-demuxer list, the list syntax and stream consistency matter. Test a short representative run and confirm that the end returns to the beginning cleanly.
If your playlist is an M3U, first determine whether it is being read as a playlist by the intended demuxer or merely as a text file with paths. Make the format explicit where needed, and check the FFmpeg output for the files it actually opens. Some playlist formats describe remote streams rather than local files; a playlist of remote sources brings additional network and reconnection behaviours that are different from a set of mounted recordings.
An alternative is to generate a new playlist or concat input when the programme changes, then restart FFmpeg deliberately. This is operationally simpler than assuming a live process will re-read a modified file, but it creates a transition and can interrupt the broadcast. If the schedule needs time-of-day changes, announcements, or separate programme blocks, consider whether a playlist process is the right tool; the workflow in running an OBS playlist of demo classes can help you compare a more interactive desktop approach.
Build the FFmpeg command and output settings
Get the command working against the exact files before adding Docker. FFmpeg commands are sensitive to option order: input options generally go before the relevant -i, while output options go after the input. A basic shape is:
ffmpeg [input options] -i /media/playlist.m3u [output options] -f flv "$YOUTUBE_RTMPS_URL/$YOUTUBE_STREAM_KEY"
This is a shape, not a ready-to-paste universal command. Replace the input options with those for the actual playlist, and choose either a transcode or stream copy based on the media. If the input codecs and stream properties are already accepted by YouTube and consistent across the playlist, stream copy avoids re-encoding. If they are not, transcode to a supported format and test that the host can sustain the encoding workload. Stream copy does not make mismatched clips consistent, and transcoding does not fix every malformed source.
YouTube recommends RTMPS and publishes encoder guidance for codec, bitrate, keyframe interval, frame rate, and audio. For H.264, the recommended bitrate for 1080p at 30 fps is 14 Mbps; YouTube lists 5 Mbps as the minimum for that resolution and frame rate. These are YouTube recommendations, not a promise of quality or a substitute for testing the connection. The same page recommends CBR, a two-second keyframe interval (not exceeding four seconds), AAC or MP3 audio, and up to 60 fps. Match the values to your selected codec and resolution rather than copying one setting to every stream.
For an H.264 transcode, the output options commonly include a video encoder, target bitrate, constant-rate control settings, a keyframe interval aligned to the frame rate, and an AAC audio encoder. Exact options depend on your FFmpeg build and the output profile you choose. Check ffmpeg -encoders in the chosen image, because an image may not include every encoder. Then run a test and inspect the YouTube preview and health indicators, as recommended in YouTube’s encoder settings guidance.
YouTube Studio supplies both an ingest server URL and a stream key. Configure both; a key is not a substitute for the server URL. Treat the key like a password: do not bake it into a Docker image, commit it to a Compose file in a public repository, or paste it into a support screenshot. Docker recommends secrets for sensitive values rather than ordinary environment variables; see its Compose secrets documentation. A local secrets file should also be excluded from version control and access-restricted if your deployment method relies on one.
Mount files and configure Compose
Use a maintained FFmpeg image you trust, pinning a deliberate version rather than assuming that latest will behave identically on a future pull. Review the image publisher’s documentation for its entrypoint and available codecs. You do not need a custom Dockerfile unless you have a reason to add tools or control the build; fewer moving parts can make updates easier to understand.
A simple Compose service can mount the media directory and run FFmpeg as its foreground command. This example leaves the loop and encoding options for you to supply, because those must match the playlist and source files:
services:
playlist-stream:
image: jrottenberg/ffmpeg:6.1-alpine
container_name: playlist-stream
restart: unless-stopped
volumes:
- ./media:/media:ro
command:
- -re
- -i
- /media/playlist.m3u
- -f
- flv
- ${YOUTUBE_RTMPS_URL}/${YOUTUBE_STREAM_KEY}
The image name and tag here are an example, not a recommendation or a claim about current image support. Check the image’s own page and verify its FFmpeg version and encoders before using it. In particular, replace the abbreviated input and output options with the tested command for your playlist. For some playlist formats, -re placement or looping options need adjustment; a command copied without testing may run too quickly, fail to loop, or fail to open media.
Compose reads a project .env file for variable substitution, but that mechanism is not a secret store. Do not put a real stream key in a file that you commit. Where supported, use Docker secrets and adapt the command or entrypoint so FFmpeg can consume the credential without exposing it in the Compose file. If your setup requires a protected local environment file, restrict access and keep it out of source control; remember that environment variables may be visible to processes or diagnostic tools.
The restart policy unless-stopped asks Docker to restart the container after an exit, except when you have deliberately stopped it. Docker documents the distinction between this and always in its restart policy reference. A restart policy cannot correct a bad playlist, expired or mistyped stream key, unreachable network, or persistent encoder error. Nor does it independently confirm that YouTube has accepted the signal.
Start, inspect, and restart the service
From the directory containing the Compose file, validate the rendered configuration before launching it. Compose can interpolate environment variables, so inspect the output carefully and do not print a real key into shared logs or a public terminal transcript. Start the service in the background with docker compose up -d, then use docker compose ps to see whether the container is running. A running state means the process has not exited; it does not certify a live broadcast.
Read recent output with docker compose logs --tail=100 playlist-stream. Look for input-open errors, decoder complaints, repeated reconnects, or output failures. Avoid sharing unredacted logs if the destination URL includes a credential. If FFmpeg exits, Compose and Docker can apply the restart policy, but a rapid failure loop needs diagnosis rather than blind waiting. Docker notes that restart policy behaviour has a startup qualification; even after automatic restarts begin, the underlying fault can remain.
Open the correct event in YouTube Live Control Room and check the incoming preview. Confirm that both picture and sound are present, that the clip changes as expected, and that stream health is acceptable before making the stream public or leaving it unattended. A representative test should include the most demanding clip and a playlist wrap-around, not merely a brief view of the first frame. Keep an eye on the host’s CPU, memory, and network use if you are transcoding; a stream-copy test has different resource demands from a transcode.
To make a deliberate update, stop or recreate the service after changing the playlist, command, or image. For example, docker compose down stops and removes the container while preserving mounted host media; docker compose up -d creates it again. If you only need to restart the same configuration, docker compose restart playlist-stream is narrower. Check the Live Control Room as the encoder comes back. At the end of a broadcast, stop FFmpeg and follow the event’s Live Control Room controls to end the stream as appropriate; stopping a container and ending the YouTube event are related but not identical actions.
Troubleshoot paths and stream errors
When FFmpeg says it cannot open the playlist or a clip, compare the host path with the container path. Run docker compose exec playlist-stream ls -l /media only while the container is running; if FFmpeg exits too quickly, use a temporary diagnostic container with the same mount instead. Check spelling, case, permissions, and whether playlist entries are absolute or relative. A path that works on the host may be meaningless inside the container unless it points under the mounted directory.
If the playlist opens but only the first item plays, revisit the playlist format and loop option. Confirm FFmpeg identifies the intended demuxer and that the playlist contains the expected entries. Test with two short clips and observe the transition, then test the wrap. If the next item fails at the boundary, inspect its codec, time base, audio layout, and timestamps; Docker will not harmonise those differences.
If the process runs but YouTube receives no signal, verify the server URL and stream key against the event in Studio, and check that the chosen protocol and output format match the encoder configuration. Do not put the key in a public issue when asking for help. Test outbound connectivity from the host and review FFmpeg’s connection messages, then check YouTube’s preview and stream health rather than treating a successful container start as success.
If video appears but audio is absent or unstable, use ffprobe on each source and check whether audio streams are present and compatible. Decide whether to map a particular audio stream, encode audio, or handle silent clips explicitly. If the stream drops during a long run, logs may show a network interruption or encoder exit; a restart can recover some process failures, but it cannot guarantee reconnection or prevent repeated failures. For a 24/7 channel, compare this hands-on maintenance with the approaches in continuous devotional streaming and choose according to who can monitor it.
Operating trade-offs and readiness checks
A Compose service is useful when you want a reproducible command, mounted files, and a process that can be restarted in a controlled way. A one-off docker run can be quicker for a temporary test, but the mounts, arguments, and restart behaviour are easier to lose or mistype. Compose keeps those choices in one configuration, which is convenient for repeat use; it does not remove the need to maintain the image and validate changes.
The following choices are worth settling before you leave a test stream running:
| Decision | When it fits | What you still need to verify |
|---|---|---|
| Stream copy | Source streams already match the output needs and remain consistent across clips | Codec support, audio presence, transitions and timestamps |
| Transcode | Sources need conversion to a consistent output | Encoder availability, host capacity, bitrate, frame rate and test health |
| Existing computer | It can remain powered and connected, and someone can maintain it | Power/network interruptions, operating-system updates and physical access |
| Rented host | You need the process away from a local computer and can administer a remote system | Provider terms, network path, storage, access security and operating cost |
Neither deployment location is automatically more reliable for your case. A local broadband connection may be suitable if it has stable upload capacity and the computer remains on; a remote host moves the workload but adds administration and cost. If the stream is on a home connection, the broadband settings checklist for a 24/7 stream is useful background, though its Windows focus means Docker networking may differ.
Before treating the system as ready, test a full representative programme, including sound, clip changes, a loop boundary, and a controlled restart. Confirm what an operator will do if the host reboots, the key is changed, storage fills, or YouTube reports a poor stream. Keep the configuration and media backed up, protect credentials, and make sure another person can find the basic recovery steps if you are away.
Technical readiness is separate from rights and channel policy. A stream that reaches YouTube can still be interrupted by a content match, and repetitive programming can have implications for monetisation review. Check current YouTube policy and your rights position; neither Docker nor a successful test stream settles those questions.
Before committing, compare the operating options on the pricing page. When the file and channel are ready, start free — 24-hour trial, no card.
FAQ
Can I loop an M3U playlist with FFmpeg in Docker?
Often, but the exact options depend on how FFmpeg is reading that M3U and whether it contains local files or remote streams. Test the demuxer, paths, transitions, and wrap-around with the FFmpeg build in your chosen image; Docker does not make an unsuitable playlist loop correctly.
Does restart: unless-stopped keep a YouTube stream live?
It tells Docker to restart a container after certain exits unless you manually stopped it. It cannot ensure that YouTube is receiving healthy audio and video, or fix a bad key, incompatible input, network problem, or repeated FFmpeg failure. Check logs and the Live Control Room after a restart.
Where should I put the YouTube stream key?
Treat it as a credential. Do not commit it to a repository or bake it into an image; use Docker secrets where supported, or a carefully protected local mechanism that is excluded from version control. Avoid sharing logs or command output that could expose it.
Do I need a VPS to run a Docker playlist stream?
No. Docker can run on an always-on computer or a remote host if it meets your operational needs. Compare power and broadband stability, remote administration, storage, and cost, then test the actual setup rather than assuming either location is inherently reliable.