A VPS can run FFmpeg continuously and send a video file, generated feed or other input to YouTube Live without keeping your personal computer switched on. The reliable workflow is to install FFmpeg, create a YouTube broadcast, test the correct input and output settings, then let systemd supervise the process.
This does not make every source media file or VPS suitable automatically. Encoding, outbound bandwidth, the input itself and YouTube's broadcast state all need checking, and a process restart is not the same as an uninterrupted broadcast.
Check the VPS and source media requirements
Start with the source rather than choosing a command copied from another setup. A looped MP4, a live network feed, a generated test pattern and a stream-copy workflow all need different FFmpeg options. The command in this guide uses a local video file as an example, but its input-specific flags are not universal.
You need an Ubuntu VPS with:
- SSH access with permission to install packages and create a system service
- Enough CPU capacity for the selected video encoder and resolution
- Sustained outbound capacity for the video and audio bitrate, with room for normal network variation
- Storage for the source file, if the input is local
- A source that can run for the intended period without ending unexpectedly
- A YouTube channel where live streaming is available
Transcoding is usually more demanding than forwarding an already compatible stream. If FFmpeg must decode the source, resize it and encode it as H.264, CPU use can become the limiting factor. If the source can be copied without changes, the CPU requirement may be lower, but the source still has to meet YouTube's accepted format and timing expectations.
Do not select VPS size from the stream title alone. Test the actual file and command on the proposed machine, then watch CPU use, memory use, disk activity and outbound traffic while the stream runs. The official YouTube guidance does not provide a universal CPU or RAM formula for FFmpeg on a VPS.
The network calculation is straightforward in principle. A video setting of 5 Mbps plus 128 Kbps of audio is already more than 5 Mbps before protocol overhead and other traffic are considered. Check the provider's current egress terms and any transfer limits yourself. The provider is a hosting choice, not a guarantee that the stream will remain connected.
Inspect the source before writing the final command:
ffprobe -hide_banner /srv/stream/input.mp4
Look for the number of video and audio streams, their dimensions, frame rate, pixel format, audio sample rate and duration. If the file has no audio, an audio option copied from another example will not create a usable audio stream by itself. If it has several audio tracks, identify which one you intend to send.
If your main concern is a file that loops without creating a new YouTube broadcast, compare the input-side considerations in how to loop a long rain video without restarting the YouTube stream. The same distinction matters for devotional recordings, ambience videos and local information loops.
Install FFmpeg on Ubuntu
This guide uses Ubuntu's APT package as a practical example. Connect to the VPS over SSH, update the package index and install FFmpeg:
sudo apt update
sudo apt install ffmpeg
ffmpeg -version
Ubuntu package versions depend on the release, architecture and repositories enabled on the particular image. Do not assume that an option available in a tutorial is present in every build. The Ubuntu package information for FFmpeg is a useful starting point for checking what the distribution provides.
The version command confirms that the executable is available and shows the build configuration. Confirm that the intended video encoder is present before you build a long-running service:
ffmpeg -hide_banner -encoders | grep -E 'libx264|h264|aac'
The exact output varies by package build. If libx264 is absent, either install a suitable package for the Ubuntu release or choose an encoder available in that build. Do not place an encoder name into a systemd service until a short manual test has accepted it.
Create a dedicated working directory rather than placing media in a personal home directory:
sudo mkdir -p /srv/stream
sudo chown -R stream:stream /srv/stream
The stream user must exist before this command. You can create a non-login service account with your normal Ubuntu administration process. The important point is to avoid running a continuously exposed media process as root unless there is a specific reason to do so.
Copy the input into /srv/stream, or make the directory available to the service account. Confirm that the account can read it:
sudo -u stream ffprobe -hide_banner /srv/stream/input.mp4
That check catches a common failure early: the administrator can read the file, but the account used by systemd cannot.
Create a YouTube Live encoder session
Open YouTube Live Control Room and create or select the broadcast you intend to use. Retrieve the stream key and the ingestion URL shown for the encoder. YouTube may show an ordinary RTMP address by default, so deliberately select or copy the secure RTMPS address.
YouTube describes RTMPS as RTMP transported over TLS/SSL and recommends it for live streaming. See the current YouTube encoder settings guidance before committing to a production setup, because available settings and requirements can change.
A stream key is a credential. Do not paste it into a public issue, repository, screenshot, shell transcript or shared support message. It is also better not to put it directly into a command that will be retained in shell history.
You can create a temporary test broadcast first. That lets you check the complete path without making the first production attempt during a scheduled programme. Use representative material: a devotional channel should test its actual audio, while an ambience channel should test the long periods of similar motion and quiet sound that the audience will receive.
The stream key connects your encoder to the selected YouTube Live session. It does not turn a local file into a broadcast by itself. You still need a running FFmpeg process, a valid input and a broadcast that YouTube accepts.
Configure the RTMPS output and input
For a local file that should loop, an illustrative command is:
ffmpeg -re -stream_loop -1 -i /srv/stream/input.mp4 \
-c:v libx264 -preset veryfast -pix_fmt yuv420p \
-r 30 -g 60 -b:v 5M -maxrate 5M -bufsize 10M \
-c:a aac -b:a 128k -ar 44100 \
-f flv "<RTMPS_URL>/<STREAM_KEY>"
Replace the input, endpoint and key. Treat this as a starting pattern, not a universal command. -re asks FFmpeg to read the file at approximately its intended playback rate. -stream_loop -1 requests an indefinite loop for a file. Remove that option for a live input or for a file that should finish.
The video options request H.264 encoding, a 30-frame-per-second output, a two-second keyframe interval when the frame rate is 30, and a constant target and maximum bitrate. The audio options request AAC stereo-compatible audio at 128 Kbps and a 44.1 kHz sample rate. The source may need other treatment if its dimensions, frame rate, rotation or audio layout do not match the output.
YouTube's encoder guidance, checked in October 2026, gives these H.264 video bitrate ranges:
| Output target | YouTube guidance for video bitrate |
|---|---|
| 720p30 | 3–8 Mbps |
| 1080p30 | 5–14 Mbps |
| 720p60 | 3–8 Mbps |
| 1080p60 | 6–17 Mbps |
These are recommended ranges, not a promise of image quality and not a substitute for testing. A 5 Mbps setting for 1080p30 may be a reasonable starting point, but the right choice depends on motion, detail, encoder behaviour and available outbound capacity. YouTube also recommends a two-second keyframe interval and says it should not exceed four seconds. Its guidance recommends 128 Kbps for stereo audio and a 44.1 kHz stereo sample rate. These figures are from YouTube's guidance verified in October 2026, not a claim about what every input or VPS can sustain.
If your source already has a suitable codec, resolution and timing, stream copying may reduce CPU use:
ffmpeg -re -stream_loop -1 -i /srv/stream/input.mp4 \
-c:v copy -c:a copy -f flv "<RTMPS_URL>/<STREAM_KEY>"
Do not use this merely because it is shorter. Copying avoids re-encoding, but it leaves the source properties unchanged. An incompatible audio codec, unusual pixel format, variable timing or unsuitable keyframe pattern can make the result less appropriate than a deliberate transcode. Read the ffprobe output and test the actual file.
For a network feed, the input URL and reconnect behaviour are part of the design. For a generated feed, the filter or source may need to be kept alive separately. For a file with no audio, you may need to generate or map audio deliberately. The FFmpeg documentation explains the available options, but the correct combination depends on the input and installed version.
Test the FFmpeg command
Run the command manually in a temporary broadcast before creating the service. Keep the terminal open and read the output rather than assuming that a connection message means the audience is receiving a healthy stream.
A successful test should cover more than whether FFmpeg stays running for a few seconds. Check that:
- YouTube receives the broadcast and shows a preview
- The picture has the intended aspect ratio and resolution
- Motion is continuous rather than frozen or rapidly skipping
- Audio is present, at the expected level and in the intended language or channel layout
- The stream health panel does not report repeated encoding or network problems
- The output remains live through a complete representative section of the source
YouTube recommends testing with audio and movement similar to the planned event and reviewing health messages during the event. A quiet rain loop can conceal a timing problem that becomes obvious when a presenter speaks or a devotional video changes scene.
Watch the FFmpeg status line for speed, frame count, bitrate and warnings. If speed remains below real time, the VPS may not encode quickly enough. If the process reports repeated input or connection errors, investigate those before adding systemd. Supervision can restart a broken command, but it cannot correct a bad path, a missing encoder or an invalid stream key.
Use a conservative first test. It is usually easier to diagnose a known local file at a modest resolution than a complex live feed with several sources. Once the basic path works, change one important variable at a time and test again.
If the image is technically live but looks soft, do not immediately increase bitrate. Inspect the source resolution, scaling, encoder settings and YouTube health messages. The practical causes are covered in why your YouTube Live stream looks blurry at high bitrate.
Run FFmpeg with systemd
After the manual command works, create a unit at /etc/systemd/system/youtube-stream.service:
[Unit]
Description=FFmpeg YouTube live stream
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=stream
WorkingDirectory=/srv/stream
EnvironmentFile=/etc/youtube-stream.env
ExecStart=/usr/bin/ffmpeg -re -stream_loop -1 -i /srv/stream/input.mp4 -c:v libx264 -preset veryfast -pix_fmt yuv420p -r 30 -g 60 -b:v 5M -maxrate 5M -bufsize 10M -c:a aac -b:a 128k -ar 44100 -f flv ${YOUTUBE_RTMPS_URL}
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Create the environment file with the combined RTMPS address and stream key:
sudo sh -c 'printf "%s\n" "YOUTUBE_RTMPS_URL=\"<RTMPS_URL>/<STREAM_KEY>\"" > /etc/youtube-stream.env'
sudo chmod 600 /etc/youtube-stream.env
sudo chown root:root /etc/youtube-stream.env
Use the real endpoint and key only on the VPS. Check systemd's environment-file and variable-substitution rules on the installed version. A wrapper script with restrictive permissions can be clearer when the command needs shell logic, several inputs or complicated quoting. Remember that ExecStart is not normally interpreted by a shell, so shell operators such as pipes and && do not work there as they would in a terminal.
Before starting, verify that the stream account can read the source and that the service account's environment file is accessible as intended. Then load, enable and start the unit:
sudo systemctl daemon-reload
sudo systemctl enable --now youtube-stream.service
sudo systemctl status youtube-stream.service
enable arranges for the service to be started during the relevant boot target. It does not prove that the broadcast is healthy. Restart=on-failure asks systemd to restart the process after an abnormal exit, and RestartSec=5 adds a delay before another attempt.
Ubuntu's systemd documentation describes restart behaviour and start-rate limiting for services. If a command fails repeatedly, systemd may stop attempting to start it according to the configured limits. That is useful protection against a rapid failure loop, but it means you should not interpret a unit's existence as proof that FFmpeg is currently connected.
A restart policy also cannot make a seamless broadcast promise. During a process exit, network interruption, VPS reboot or YouTube-side failure, the outgoing stream can stop or enter a recovery state. The next FFmpeg process may reconnect to the same broadcast, or YouTube may require a new session depending on what happened. Test this behaviour rather than assuming that a restarted process means an uninterrupted audience experience.
Check logs and stream health
Follow the service log while testing:
sudo journalctl -u youtube-stream.service -f
For a recent window, use:
sudo journalctl -u youtube-stream.service --since "30 minutes ago"
Check the unit state separately:
systemctl is-active youtube-stream.service
systemctl show youtube-stream.service -p ExecMainStatus -p NRestarts
A running process is only one signal. Also open YouTube Live Control Room and check the preview, stream health messages, audio and the broadcast status. A process can remain active while reading a stalled input, repeatedly failing to deliver useful media or sending the wrong broadcast.
When diagnosing a failure, classify it before changing settings:
| Symptom | First checks |
|---|---|
| FFmpeg exits immediately | Input path, permissions, encoder availability and command syntax |
| Authentication or connection failure | RTMPS URL, stream key, selected broadcast and outbound firewall rules |
| CPU stays high and speed falls below real time | Resolution, frame rate, preset, scaling and whether stream copy is appropriate |
| Picture appears but audio is missing | Input audio streams, mapping, codec and audio format |
| Service restarts repeatedly | Full journal, source availability, YouTube response and systemd rate limits |
| Broadcast stops after the file ends | Whether -stream_loop -1 is appropriate for that input |
Do not paste the complete journal into a public forum without removing the stream key and any private paths. If you rotate the key in YouTube, update the protected environment file and restart the service deliberately.
For a channel that must operate overnight, add a simple human check to the routine. Review the stream before leaving it unattended, inspect the service after a planned reboot, and check the YouTube preview rather than relying only on systemctl is-active. If you need several channels on one machine, CPU, disk and egress contention become shared failure points; how to manage several 24/7 YouTube channels from one VPS in India covers the operational trade-offs.
If you do not want to maintain a VPS, FFmpeg installation and systemd unit, StreamNeo removes that particular maintenance task: upload the video, provide the YouTube stream key, and let the cloud-run broadcast handle process monitoring and automatic restarts while your computer is off. It remains your responsibility to use suitable content, confirm the YouTube broadcast and check the resulting stream.
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
Does systemd guarantee a continuous YouTube broadcast?
No. Restart=on-failure helps bring FFmpeg back after a process failure, but it does not prevent a gap or repair a failed VPS, network path, input file, stream key or YouTube broadcast. Test the recovery path and monitor YouTube's stream health as well as the service state.
Can I use one FFmpeg command for every video file?
No. The input's codecs, dimensions, frame rate, audio streams and timing affect the correct options. Inspect each source with ffprobe, then decide whether to transcode, copy, map or generate streams before placing the command in systemd.
Should I use RTMP or RTMPS?
Use the secure RTMPS ingestion address when YouTube provides it. Verify the selected URL in Live Control Room rather than assuming that the first address displayed is the secure one.
Why is FFmpeg running but YouTube shows no healthy stream?
Check the journal for connection and encoding errors, then check the broadcast preview and stream health in YouTube Live Control Room. Confirm the endpoint, stream key, output format, audio presence, bitrate and VPS outbound connectivity. A running FFmpeg process alone does not confirm that YouTube is receiving usable media.