If you have a Debian VPS and a media source, FFmpeg can publish it continuously to YouTube Live without leaving your own computer switched on. The dependable setup is not one command: you need to prepare the source, obtain the current YouTube ingest details, match the encoder settings, test the result, and supervise the process.
This guide uses a looping video file as its main example. A live capture source or generated feed follows a different pattern, so those cases are separated rather than hidden behind an assumed input.
Choose and prepare the Debian VPS
A VPS is the computer that will read your source, encode it if necessary, and send the result to YouTube. Before choosing one, estimate the requirements of the actual channel rather than selecting a plan because its label sounds suitable.
The important factors are sustained outbound capacity, the provider’s transfer allowance, CPU capacity if FFmpeg will encode in software, available memory, storage for the media and logs, and the provider’s support and uptime terms. YouTube’s published ingest rates help you estimate the stream’s network requirement, but they do not establish that any particular VPS plan or provider will be suitable. Check the plan and region you intend to use.
For a first H.264 example, YouTube currently recommends 5 Mbps for 720p30, 8 Mbps for 720p60, 14 Mbps for 1080p30, and 17 Mbps for 1080p60. These are video bitrate recommendations, not a complete network allowance. Audio, transport overhead, other traffic, and variation in the connection need room as well.
Choose a Debian release that your provider currently offers and that you are prepared to maintain. After connecting, update the package index and installed packages, create a separate administrative user if your provider’s image has not already done so, and use SSH keys where possible. The commands below assume a user with sudo access and paths under /srv/stream.
sudo apt update
sudo apt full-upgrade
sudo mkdir -p /srv/stream/media /srv/stream/logs
Keep media, configuration, and logs separate. A video file filling the disk should not silently prevent logs or system updates from being written. Check free space before transferring a large file and decide how old logs will be retained.
A VPS gives you control over the operating system and process manager, but it also gives you responsibility for updates, credentials, firewall rules, resource pressure, and diagnosis. If you want to compare this operating model with alternatives that do not depend on a machine you maintain, the discussion in YouTube 24/7 live stream with a playlist: OBS or cloud service is a useful starting point.
Install and inspect FFmpeg
Install FFmpeg from Debian’s package repositories unless you have a specific reason to use another build.
sudo apt install ffmpeg
ffmpeg -version
ffmpeg -encoders | grep -E 'libx264|aac'
ffmpeg -protocols | grep -E 'rtmp|rtmps'
The first command installs the package. The other commands are inspections, not guarantees that every encoder or protocol combination will work with your source. Confirm that the build includes the video and audio encoders you plan to use and that the protocol support is present.
Inspect the input before constructing the output command. ffprobe is installed with FFmpeg on many Debian packages, and it can show the streams, duration, frame rate, pixel format, and audio properties.
ffprobe -hide_banner /srv/stream/media/program.mp4
Look for more than the file extension. A file may contain video without audio, variable frame rate video, an unusual pixel format, or a codec that you do not intend to copy to YouTube. Decide whether FFmpeg will copy compatible streams or decode and encode them into a known output profile. For a continuous channel, predictable output is usually easier to test than passing through every property of every source file.
FFmpeg’s own documentation describes the RTMP protocol and its URL structure. You can read the FFmpeg RTMP protocol documentation when checking options for a particular build. RTMPS is the secure SSL/TLS form of the protocol, but a keepalive option is not the same thing as a process watchdog or an application-level recovery strategy.
Prepare the source: file, playlist, or live feed
A stored file is the simplest source to reason about. The -re option tells FFmpeg to read the input at its native rate, which matters when a file is being published as live content. Without it, FFmpeg may read and encode the file faster than real time, causing the output to run ahead or end quickly.
For one file repeated indefinitely, a representative input pattern is:
-re -stream_loop -1 -i /srv/stream/program.mp4
This is an input pattern, not a complete deployment command. -re belongs before the input it applies to. -stream_loop -1 requests indefinite repetition for that input, but you should test how the selected FFmpeg build handles the file boundary, timestamps, and audio when the loop begins again.
A playlist is a different problem. It may be assembled by concatenating compatible files, using a concat demuxer, or by running a controlling script that moves from one item to the next. The files need compatible stream properties if you want clean transitions. Test the boundary between two files, not just the first few minutes of the first file. A file that reaches end-of-file with no replacement will leave the encoder with no useful input even if the process itself remains running.
A live capture source, such as a camera or another capture device, does not need -re in the same way because the source already arrives in real time. A generated feed may need its own timing mechanism. A network input can stop advancing while FFmpeg remains alive. For each source type, identify what indicates healthy progress and what should happen when the source disappears.
The source also needs to be yours to use. Check the rights, licences, music permissions, and YouTube policies that apply to the material and channel. A technical setup does not decide whether a particular recording can be broadcast. For devotional, educational, or local programming, keep a written record of the files and permissions you rely on. If your project is mainly a playlist, how to make a YouTube Live stream play videos in order covers the content-order problem separately from VPS supervision.
Create the YouTube broadcast and copy its ingest details
Open YouTube Live Control Room and create or schedule the broadcast according to the channel’s workflow. YouTube separates the broadcast from the incoming stream feed, so confirm that the broadcast is scheduled, live, or configured as intended before troubleshooting FFmpeg.
In the Stream settings, reveal and copy the current RTMPS URL and the stream key. YouTube’s official encoder streaming settings describe the current flow and recommended encoder requirements. Use the precise endpoint shown for your account rather than an old URL copied from a tutorial. Check that the scheme is rtmps when you intend to use encrypted transport.
The full URL shape is account-facing configuration. Some instructions show a server URL and a key appended to it, while an account may provide a complete value or a particular path. Follow the instructions shown in Live Control Room and validate the final combination with a short test. Do not assume that an illustrative endpoint found elsewhere is correct for every channel.
Treat the stream key as a password. Do not place a real key in a public article, shell history, repository, screenshot, or world-readable service file. Store it in a protected file or credential mechanism readable only by the service account. If it is exposed, rotate it through YouTube’s controls.
One practical approach is to keep the URL and key in a root-owned environment file with restricted permissions, then have the service read it. Avoid putting the secret directly into a command that you may later paste into a support forum. The file should be checked with ls -l and should not be readable by ordinary users.
Configure FFmpeg output for the chosen source
For a first test, use a conservative SDR profile such as H.264 video at 720p30 with AAC stereo audio. This is an example profile, not a universal requirement. Choose the output resolution, frame rate, codec, and bitrate to match your source, VPS capacity, and YouTube’s current guidance.
YouTube currently recommends constant bitrate, progressive video, square pixels, and a two-second keyframe frequency, with a maximum of four seconds. Its guidance also covers codec, colour, profile, and audio requirements. For stereo audio, it recommends 44.1 kHz and 128 kbps; surround audio has different settings. Review the current YouTube live encoder requirements before fixing a production profile, especially if you are preparing HDR rather than SDR.
A command pattern for a looping file is:
ffmpeg -re -stream_loop -1 -i /srv/stream/media/program.mp4 \
-c:v libx264 -preset veryfast -b:v 5M -maxrate 5M -bufsize 10M \
-r 30 -g 60 -keyint_min 60 -sc_threshold 0 \
-c:a aac -b:a 128k -ar 44100 \
-f flv "${YOUTUBE_RTMPS_URL}/${YOUTUBE_STREAM_KEY}"
This is an illustrative pattern, not a tested command for every Debian build, input, or account. The -g 60 and -keyint_min 60 values represent two seconds only at 30 frames per second. If you select another frame rate, calculate the keyframe interval from that rate and check the result in YouTube’s health display.
The example requests H.264 encoding with a constant target rate, AAC audio, and FLV output for the RTMPS connection. The -preset setting affects the CPU and quality trade-off. A slower preset can require more CPU; a faster preset may reduce CPU pressure while changing compression efficiency. Watch the actual VPS load rather than assuming the preset will suit every source.
Set YOUTUBE_RTMPS_URL and YOUTUBE_STREAM_KEY through a protected mechanism in the session or service. Do not put a real key into a globally readable systemd unit. Some YouTube configurations provide a complete stream URL or expect the key in a particular position, so confirm the final URL shape with the account’s Live Control Room.
For a live capture or generated feed, replace the file input and remove file-specific loop options. Keep the output settings tied to the selected source. If the incoming feed is already encoded and compatible, copying may reduce CPU use, but it also passes through properties that may not meet the intended YouTube profile. Re-encoding gives you more predictable output at the cost of CPU.
Test the stream before relying on it
Do not make a newly assembled command your overnight deployment. Run it interactively with media that resembles the final channel: the same kind of motion, audio levels, resolution, frame rate, and file transitions. Keep the terminal available so you can read FFmpeg’s stderr output.
Open the YouTube preview and inspect stream health. Check for a picture, clear audio, stable motion, and a sensible incoming bitrate. YouTube’s health information can identify issues such as unsupported codecs, a bitrate that is too low, a frame-rate mismatch, a mismatched keyframe frequency, or insufficient incoming video that may cause viewer buffering. Read the message rather than treating a warning as a generic network problem.
Test more than the initial connection. Let the file reach a loop boundary, stop and start the service deliberately, reboot the VPS if that is part of your recovery plan, and observe what happens when the input file is missing or the network connection is interrupted. These tests reveal which failures are handled by the process manager and which require an operator or a separate design.
Watch the VPS while the test runs:
top
df -h
free -h
Check whether CPU use remains sustainable, whether memory pressure appears, whether the disk has room for logs and media, and whether the output is leaving the host at the intended rate. A stream that looks fine for a short preview can still fail when the input loops, the process is restarted, or the machine remains under load for longer.
If viewers report buffering, separate the possible causes. Inspect the encoder output and YouTube’s health messages first, then examine VPS CPU, network capacity, and the viewer’s connection. The guide to encoder-side and viewer-side buffering fixes helps keep those two sides from being treated as one fault.
Supervise the process and review logs
An always-on channel needs more than an SSH session. Configure a service manager to start FFmpeg after boot, run it under a dedicated unprivileged user, restart it when the process exits, and send logs to a place you can inspect. On Debian, systemd is a practical choice, but the exact unit must be validated on the Debian release and paths you use.
Create a dedicated account with access to the media and protected configuration, but not unnecessary administrative privileges. A unit might contain settings in this general form:
[Unit]
Description=YouTube FFmpeg stream
After=network-online.target
Wants=network-online.target
[Service]
User=streamer
EnvironmentFile=/etc/stream/stream.env
ExecStart=/usr/bin/ffmpeg -re -stream_loop -1 -i /srv/stream/media/program.mp4 -c:v libx264 -preset veryfast -b:v 5M -maxrate 5M -bufsize 10M -r 30 -g 60 -keyint_min 60 -sc_threshold 0 -c:a aac -b:a 128k -ar 44100 -f flv ${YOUTUBE_RTMPS_URL}/${YOUTUBE_STREAM_KEY}
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Treat this as a starting shape, not a guarantee. Quote and escape values correctly for the unit format, confirm how the protected environment file is read, and test the exact command interactively first. A service can restart a process that exits, but it cannot by itself determine that a process is alive while the source is stalled or YouTube is no longer receiving useful video. Restart=always is not recovery from every condition.
After creating the service, check its status and logs:
sudo systemctl daemon-reload
sudo systemctl enable --now stream.service
sudo systemctl status stream.service
sudo journalctl -u stream.service -n 100 --no-pager
sudo journalctl -u stream.service -f
Keep an eye on restart counts, repeated connection errors, input end-of-file messages, encoder warnings, and timestamp problems. Set a sensible retention policy so journal growth does not consume the disk. Also review the media path, permissions, service account, and environment file after every change.
Your operating checklist should include the service state, recent FFmpeg output, CPU and memory pressure, disk space, the input’s progress, YouTube’s preview and health messages, and the broadcast’s lifecycle state. If the broadcast has ended or is still scheduled, restarting FFmpeg alone may not produce the result you expect. YouTube broadcast settings and the incoming stream feed are related but separate parts of the operation.
For creators who do not want to maintain a Debian host, package updates, SSH sessions, and process supervision, StreamNeo removes the VPS maintenance step by taking an uploaded video and running the YouTube stream without your computer remaining on. That is a different operating model, not a Debian deployment, and it remains YouTube-only.
A practical handover checklist
Before calling the channel unattended, confirm each item below:
| Area | Check before leaving it running |
|---|---|
| VPS | The selected plan’s CPU, outbound capacity, transfer allowance, storage, and support terms match the intended workload |
| Input | The file, playlist, capture source, or generated feed advances correctly and behaves as expected at boundaries |
| FFmpeg | The installed build includes the required encoders and protocols, and the command works outside systemd |
| YouTube | The current RTMPS URL and key came from Live Control Room, and the broadcast state is correct |
| Output | Codec, audio, resolution, frame rate, bitrate, and keyframe interval match the intended profile |
| Security | The key is protected, the service uses a dedicated account, and no secret appears in public logs or repositories |
| Monitoring | You can inspect service status, journal output, resource use, input progress, and YouTube stream health |
| Recovery | You have tested process exit, reboot, missing input, loop boundaries, and a temporary connection failure |
Keep this checklist with the channel documentation. When a stream fails overnight, the useful question is not only whether FFmpeg restarted. It is whether the input progressed, whether YouTube received a healthy feed, whether the broadcast was still active, and whether the service had the permissions and resources it needed.
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
How do I keep an FFmpeg YouTube stream running after an SSH disconnect?
Run FFmpeg under a service manager such as systemd rather than as an ordinary foreground process in an SSH session. Configure startup, restricted permissions, logs, and a restart policy, then verify the behaviour after disconnecting and rebooting. A restart policy does not detect every stalled input or unhealthy remote feed.
How do I stream a video file to YouTube Live with FFmpeg?
Use -re before the file input so stored media is read at real-time speed, and use a deliberate looping or playlist method if the content must continue. Encode the output to a profile that matches YouTube’s current guidance, then copy the current RTMPS URL and stream key from Live Control Room. Test the file boundary and stream health before leaving it unattended.
Should I use RTMP or RTMPS?
YouTube recommends RTMPS for encoder delivery because it carries RTMP over TLS/SSL. Copy the exact RTMPS endpoint shown in Live Control Room and check both the protocol and server if an SSL connection fails. Do not rely on an old example URL from another account or tutorial.
Can FFmpeg guarantee an uninterrupted 24/7 broadcast?
No. FFmpeg and systemd can be configured to reduce manual intervention, but a source can stop advancing, the VPS can run short of resources, the network can fail, or YouTube can report an unhealthy feed. Continuous operation requires testing, logs, monitoring, and a recovery plan suited to the particular source.