Skip to content
streamneo.
Setup Guides14 min read

How to Use FFmpeg to Stream a Playlist from a VPS to YouTube over RTMPS

Separate playlist preparation from YouTube RTMPS settings, then configure FFmpeg on a VPS with a cautious validation path.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

FFmpeg can read media from a VPS, encode it as a live feed, and send that feed to YouTube over RTMPS. The reliable method is to handle two separate jobs: first make sure FFmpeg can read and sequence your playlist, then configure the YouTube destination and live output.

There is no single playlist command that fits every media set. A local concat list, an M3U or M3U8 source, and a directory of mixed files have different requirements, so validate the input before choosing the final command.

What kind of playlist are you streaming?

The word “playlist” can describe several different inputs. Before touching the YouTube settings, identify what you actually have on the VPS.

A common case is a plain text file used by FFmpeg’s concat demuxer. It contains one media path per line, for example:

file '/home/stream/media/intro.mp4'
file '/home/stream/media/main.mp4'
file '/home/stream/media/outro.mp4'

This is not the same thing as an M3U playlist. An M3U or M3U8 file may contain local paths, HTTP URLs, stream metadata, or segments for an HLS stream. A media player may open it successfully while FFmpeg needs a different input format or additional handling. Do not rename a file extension and assume that the input semantics have changed.

The concat demuxer is most predictable when the listed files have matching stream properties. Similar video dimensions, frame rates, codecs, audio layouts and time bases reduce the chance of transitions, timestamp problems or unexpected output. FFmpeg’s concat demuxer documentation also warns that inaccurate durations can produce artefacts, particularly when a file contains unusual timestamps or a stream ends earlier than its container indicates.

Check each file before building a continuous stream. ffprobe, which is normally distributed with FFmpeg, can show the video codec, dimensions, frame rate, audio codec, sample rate and duration:

ffprobe -v error -show_entries \
format=duration:stream=index,codec_type,codec_name,width,height,avg_frame_rate,sample_rate,channels \
-of default=noprint_wrappers=1 'media/main.mp4'

Run it against each file, not only the first one. If the files differ substantially, you may need to transcode them into a common intermediate format before using the playlist. That takes extra storage and processing time, but it is often easier to diagnose than a live command that fails only at the second or third item.

If your source is a set of lofi videos, devotional recordings or lectures, the guide to looping lofi videos on a 24/7 YouTube Live stream covers the broader programming choices. Here, the important distinction is that playlist sequencing is an input problem, while RTMPS is an output problem.

Prepare the VPS and FFmpeg

A VPS needs enough CPU, memory, storage and outbound network capacity for the job. The exact requirement depends on the source resolution, frame rate, encoder, number of streams and whether FFmpeg is decoding and re-encoding every file. The available VPS package name alone does not tell you whether it can encode your chosen output in real time.

Install FFmpeg from a trusted distribution source or use a build whose enabled codecs and protocols you have checked. Different packages can be compiled with different options. Confirm the executable and inspect the available encoders:

ffmpeg -version
ffmpeg -encoders | grep -E 'libx264|aac|nvenc|vaapi|qsv'

The exact encoder list is not a promise that every listed encoder will work on your VPS. Hardware encoders may need compatible virtualised hardware and drivers, while software encoders use CPU. Start with a short test rather than committing to a full night of streaming.

Create a directory with controlled permissions for the media and playlist. Keep paths simple while testing, and use absolute paths in the concat file. If filenames contain apostrophes, line breaks or unusual characters, check the concat demuxer’s quoting rules rather than copying a shell-escaped path into the file without testing it.

The -safe 0 option is often used when a concat list contains absolute paths. It relaxes FFmpeg’s safety checks, so it should not be treated as a general fix. Use it only with a playlist and files you control. Do not put arbitrary remote or user-supplied paths into a production list.

You also need a plan for logs and restarts. Run a first test in the foreground so that errors are visible. Once the input and output work, use a process supervisor or a carefully tested service arrangement appropriate to your VPS. A restart policy can bring a process back after a failure, but it cannot correct a bad playlist, an expired key or insufficient CPU.

For a comparison of the practical trade-offs around remote operation, see the guide to running a 24/7 prerecorded YouTube stream on a VPS. Treat provider capacity and network performance as things to test rather than as guarantees attached to a product label.

Retrieve YouTube’s RTMPS destination and stream key

YouTube must be ready to accept a live encoder connection before FFmpeg can send anything useful. Live streaming must be enabled for an eligible, verified channel. YouTube says the channel must not have had live-streaming restrictions in the preceding 90 days, and the streamer must be at least 16 years old. Check the current requirements in YouTube’s live-streaming eligibility guidance.

Open YouTube Studio and enter Live Control Room. Create or select the stream, choose an encoder workflow, and copy the server URL and stream key shown for that stream. Do not substitute a URL found in an old tutorial. YouTube notes that RTMPS may not be the default URL displayed, so explicitly retrieve the RTMPS endpoint when that is the protocol you intend to use.

RTMPS is RTMP carried over a TLS or SSL connection. In FFmpeg, the destination normally appears as an RTMPS URL followed by the host, application path and stream key supplied by YouTube. Keep the URL as one complete value, and do not independently invent the application path.

Treat the stream key as a password. YouTube describes stream keys as both the password and address for a stream. Do not paste the real key into a public tutorial, a support ticket or a screen recording. It is also worth remembering that shell history can retain commands. You can reduce exposure by using a protected script or another secret-handling method rather than typing the key into a shared terminal session.

If you believe the key has been exposed, reset it in Live Control Room and update the sender. A reset key will not repair a command that still contains the old value.

The destination and key belong to YouTube’s stream setup. They do not tell FFmpeg how to read your media, and a correct key cannot compensate for a playlist that contains incompatible files.

Choose the input method for your playlist

For a local concat-demuxer list, an illustrative command shape is:

ffmpeg -re -stream_loop -1 -f concat -safe 0 -i playlist.txt \
  -c:v libx264 -preset veryfast -b:v 4500k -maxrate 4500k -bufsize 9000k \
  -r 30 -g 60 -c:a aac -b:a 128k -ar 44100 \
  -f flv 'rtmps://INGEST_HOST/APP/STREAM_KEY'

This is a template, not a universal or verified command. Replace the destination only with the RTMPS URL and stream key shown in Live Control Room. The bitrate and encoder settings must match the resolution and frame rate you have selected, as well as the capacity of your VPS.

The -f concat option tells FFmpeg to use the concat demuxer, while -i playlist.txt identifies the list. -stream_loop -1 requests indefinite looping of the input. -re reads the input at approximately its native playback rate instead of pushing a file as quickly as the machine can process it. It is useful for file-based live output, but it does not make a broken playlist valid.

If your playlist is an M3U or M3U8 URL, stop before copying this command. That source may be a collection of files, an HLS presentation, or a continuously updated network stream. It may require a direct URL as the input, different reconnect behaviour, or no looping at all. Test the source independently with FFmpeg and inspect the first errors before adding the YouTube output.

For a local list, begin with one file and then add the others one at a time. This shows whether the failure occurs during input opening, at a transition, during decoding, or only after the output connection is established. It also avoids trying to debug a playlist and a remote publishing connection simultaneously.

The files do not have to be visually identical, but a common output is easier when they are consistent. Mixed frame rates can create timestamp changes. Mixed audio sample rates or channel layouts can create audio transitions. A damaged file may work in a desktop player and still fail when FFmpeg reads it continuously.

If your aim is to change the sequence while a channel remains online, read about changing the playlist on a running 24/7 YouTube stream. That operational problem is different from starting one static concat list and leaving it untouched.

Pace and send the output

After the input is known to work, configure the encoded output. YouTube’s encoder guidance for RTMP and RTMPS includes H.264, H.265 and AV1 video, AAC or MP3 audio, and frame rates up to 60 fps. Your FFmpeg build and the selected YouTube workflow still need to support the combination you choose.

For a straightforward VPS setup, H.264 with AAC is often easier to test because the command and receiving side are widely understood. That is a compatibility choice, not a claim that it is always the best encoder. H.265 or AV1 may be appropriate in a particular workflow, but compare codec support, CPU use, hardware availability and receiving requirements before changing the example.

YouTube recommends constant bitrate for this type of encoder connection. Its settings guidance also recommends a two-second keyframe interval and says not to exceed four seconds. In the example, 30 frames per second with -g 60 gives a nominal two-second GOP. If you use another frame rate, calculate the keyframe interval accordingly and confirm the result rather than copying -g 60 unchanged.

Choose the bitrate from YouTube’s current table for the resolution and frame rate you are sending. The value in the example is not a universal recommendation. A 720p stream, a 1080p stream and a low-motion audio channel with a static visual do not automatically have the same useful target.

Setting What it controls What to check
-c:v Video encoder The codec is available in your FFmpeg build and suitable for the workflow
-b:v and -maxrate Video bitrate The target matches YouTube’s guidance for the chosen resolution and frame rate
-bufsize Rate-control buffer The value is appropriate for the selected bitrate and encoder
-r Output frame rate The source and YouTube configuration can handle the chosen rate
-g Keyframe spacing The resulting interval is about two seconds and does not exceed four seconds
-c:a, -b:a, -ar Audio encoding The audio codec, bitrate and sample rate match your intended output
-f flv Output container for RTMP-family publishing It is paired with the RTMPS destination rather than a file output

YouTube’s advanced recommendations include 44.1 kHz and 128 Kbps for stereo audio. That does not mean every source should be forced to those values without testing. If the source has unusual channel layouts or already contains synchronisation problems, inspect it first.

Allow network capacity for the complete encoded feed. YouTube recommends 20% upload bandwidth headroom beyond the combined primary and backup stream bitrates. If you send only one feed, that still leaves room for ordinary variation and protocol overhead. Measure the VPS’s actual outbound performance rather than relying only on a host’s advertised port speed.

Start with a short publishing test and watch CPU usage, memory, upload rate and FFmpeg’s timestamps. A command that stays connected for a few minutes is not proof that it will survive an overnight run, but it can expose a wrong URL, unsupported encoder or transition failure before you depend on it.

Validate the stream in YouTube Live Control Room

Do not judge success only by seeing an FFmpeg process running. A process can be active while YouTube receives no usable video, receives silence, or is still waiting for a keyframe.

Open Live Control Room and confirm that the incoming preview appears. Check the preview for moving video, audible audio and sensible synchronisation. For a scheduled stream, follow YouTube’s workflow and click Go live only after the preview and stream health are acceptable. For other workflows, use the controls shown for the stream you created.

Keep the FFmpeg terminal visible during this first validation. Look for repeated connection failures, decoder errors, dropped output, non-monotonic timestamps and messages showing that the process has stopped reading the playlist. Save enough log output to identify the point at which a problem begins.

Check the output at the resolution and frame rate you intended. A source file may be 1080p while the output is being scaled, or the encoder may be reducing the frame rate because the VPS cannot keep up. Confirm what YouTube reports rather than inferring it from the source filename.

Monitor the stream continuously when it becomes operational. YouTube’s streaming guidance recommends monitoring stream quality, and a remote process can continue running after the useful output has stalled. Watch the YouTube health indicators as well as the VPS process and network activity.

When you stop the operation, end the stream in YouTube and then stop FFmpeg. YouTube says streams under 12 hours are automatically archived. Do not assume that a long-running playlist becomes one complete archive, or that stopping and restarting has the same archive behaviour as one continuous session.

Troubleshoot common connection and playlist issues

There is no incoming preview. Recopy the RTMPS URL and stream key from the current Live Control Room session. Check that the key has not been reset, that it has not been inserted into the wrong part of the URL, and that the VPS can make outbound connections on the required path. Test the same input locally or to a file first so that you know FFmpeg is producing output.

FFmpeg reports an unsupported protocol or encoder. Inspect ffmpeg -version, the protocol list and the encoder list on that VPS. A package installed from one repository may not include the same features as a build used in another guide. Installing a different build may solve the missing feature, but verify what changed instead of assuming every binary named ffmpeg is equivalent.

The command fails when the second file begins. Test that file by itself, then compare its streams with the preceding file. Mismatched dimensions, codecs, frame rates, audio layouts or inaccurate durations can become visible only at the transition. Re-encode the set to a consistent intermediate format if correcting the original files is impractical.

The stream plays too quickly or buffers at a transition. Confirm that -re is applied to the file-based input and that the command is not reading a source as fast as possible. For a network playlist, do not assume -re solves every pacing issue. The source type may already be live-paced, or it may need input-specific reconnect and buffering settings.

The video freezes while FFmpeg remains active. Check CPU load, encoder speed, memory pressure and upload capacity. A VPS can stay connected while falling behind real time. Reduce the output resolution or frame rate for a test, or use an encoder that your particular machine can sustain. YouTube’s settings table is a receiving guide, not a benchmark for your VPS.

Audio and video drift apart. Inspect the source timestamps and compare audio properties across files. Long streams can expose small timing differences that are not obvious in a short test; the causes and remedies are covered in the article on audio out of sync on long streams. Avoid adding timestamp flags at random, because they can hide the input problem while creating a different one at the next transition.

The connection drops overnight. Look at the FFmpeg log, VPS monitoring and YouTube health history to distinguish an input failure, process exit, network interruption or key problem. A supervisor can restart a process after an exit, but it will not make a damaged file playable. If maintaining the VPS process, playlist and restart handling is the part that keeps failing, StreamNeo removes that specific operational burden by letting you upload the video, provide the YouTube stream key and leave the cloud stream to run while your computer is switched off.

The stream is visible but marked with poor health. Recheck bitrate, keyframe spacing, frame rate and network headroom. YouTube recommends allowing 20% beyond the combined primary and backup bitrate, and a congested VPS connection can affect an otherwise valid command. Change one setting at a time and repeat the short validation rather than replacing the entire command without knowing which part mattered.

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 use any M3U playlist with FFmpeg?

No. M3U is a container for entries, not a guarantee that every entry has the same media type or that FFmpeg can read it in the same way. Inspect whether it contains local files, direct media URLs, or HLS segments, then test that source format separately from the YouTube output.

Is the example command suitable for every VPS?

No. It is an illustrative concat-demuxer template. Your VPS must sustain the selected decode and encode workload, your FFmpeg build must contain the required codecs and protocols, and the media files must be compatible enough for the chosen input method.

Where do I get the YouTube RTMPS URL and key?

Get both from the encoder stream in YouTube Live Control Room. Use the RTMPS endpoint shown there rather than copying a URL from an old guide, and treat the key as a password that must be reset if it is exposed.

Should I loop the playlist indefinitely?

Use -stream_loop -1 only when the input method and playlist have been tested to loop correctly. An indefinite loop does not repair bad durations, incompatible files or timestamp errors, so validate one complete pass before relying on continuous operation.

YOU’VE REACHED THE END

Keep the ideas coming.

More guides, useful tools and a little help for your next broadcast.

Back to the journal ↗
YOUR NEXT READ

A little more to explore.

More Setup Guides guides ↗ · All topics ↗