Skip to content
streamneo.
Troubleshooting13 min read

How to Restart an FFmpeg YouTube Stream Automatically on a VPS

Use systemd to restart FFmpeg after failure, add careful output recovery, and verify that YouTube is receiving the stream again.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

A reliable way to relaunch an FFmpeg YouTube stream on a VPS is to run FFmpeg as a systemd service with a failure restart policy. For some output failures, FFmpeg's FIFO muxer also has recovery controls, but that is a different layer from restarting a process that has exited.

Neither method guarantees that YouTube restores the same live event, input position, or viewer playback. After recovery, check the service journal and YouTube Live Control Room rather than treating an active process as proof that viewers are receiving audio and video.

Identify the failure before choosing the recovery

There are two failures that are often described as “the stream stopped”, but they need different responses.

First, FFmpeg may still be running while an output path is temporarily unable to write. A network interruption, a protocol-level error, or a problem handled by the selected output muxer can leave the process alive while no useful stream reaches YouTube. An in-process recovery setting may help in some of these cases.

Second, FFmpeg may exit. This can happen because the input file ended, the command is invalid, the stream key is rejected, the input disappears, or FFmpeg encounters an error it cannot continue through. A FIFO option cannot supervise a process that no longer exists. A service manager such as systemd is the layer that can start a new FFmpeg process.

The distinction matters because a green process check is not enough. If FFmpeg remains alive but is stuck on an output error, systemd may see no failure and do nothing. If FFmpeg exits, a correctly configured systemd unit can launch it again, but the new process starts according to the command you give it. It does not automatically know which point in a playlist or video you intended to resume.

Before changing anything, reproduce the failure if you can and record what happened. Note whether the process exited, whether the input was still readable, what FFmpeg printed at the end, and what YouTube showed in Live Control Room. For a looped channel, it is also useful to decide whether a failed launch should retry indefinitely or stop after repeated failures for manual inspection.

If the underlying stream is built from pre-recorded material, first make sure the command itself is sound. The guide to setting FFmpeg to loop a video forever covers the input-side behaviour. Supervision can relaunch a good command, but it cannot repair a missing file, an incorrect option, or a source that is permanently unavailable.

A useful comparison is:

Recovery layer When it acts What starts the next attempt What it does not prove
FFmpeg output recovery FFmpeg is still running and the selected output path supports the recovery controls The relevant FFmpeg muxer or output path That YouTube has restored the event or that viewers saw continuous playback
systemd restart The service process exits under the configured restart conditions systemd, after the configured delay That the command, credentials, input, or YouTube ingest is now healthy

Treat these as complementary controls, not interchangeable alternatives.

Run FFmpeg under systemd

A systemd unit gives the VPS a defined service to start, stop, inspect, and restart. It also makes the stream independent of an SSH session. If you currently launch FFmpeg from a terminal or a shell session that closes overnight, move the same working command into a service before diagnosing restart behaviour.

Create a dedicated unit, using the naming and directory conventions of your Linux distribution. A minimal example is:

[Unit]
Description=YouTube FFmpeg stream
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=stream
ExecStart=/usr/local/bin/start-youtube-stream
Restart=on-failure
RestartSec=15s

[Install]
WantedBy=multi-user.target

The ExecStart line points to a wrapper script in this example rather than displaying a working stream command. That script should run the tested FFmpeg command in the foreground. Do not use a shell command that backgrounds FFmpeg, because systemd then monitors the shell instead of the long-running encoder process.

The User value should be a dedicated account with access to the input files, the wrapper, and any required device or directory. It should not need broad administrative access just to publish a stream. Make the wrapper executable and restrict its ownership and permissions according to your distribution's conventions.

The unit is not universal across Debian, Ubuntu, Fedora, or other Linux distributions. Paths, package names, the available systemd version, and local security settings differ. Use the installed systemd.service manual and your distribution documentation when adapting the example.

After placing or changing a unit, ask systemd to read the definition again, then enable and start it using the normal administrative commands for your distribution. A typical sequence is:

sudo systemctl daemon-reload
sudo systemctl enable --now youtube-stream.service
sudo systemctl status youtube-stream.service

The service name in those commands must match the filename you chose. Enabling the service controls whether it starts during boot; it does not by itself confirm that YouTube is receiving a valid stream. Start with status, then inspect the journal and the YouTube-side health indicators.

This arrangement is useful even if you are still deciding whether a VPS is the right operating model. The practical differences between running a stream on your own computer and hosting a 24/7 YouTube live stream on a VPS include how you handle power, reboots, network changes, and unattended recovery.

Set a restart policy and backoff

Restart=on-failure tells systemd to restart the service when the process fails rather than when an operator deliberately stops it. That distinction helps prevent a normal administrative stop from immediately launching the stream again. The systemd project describes Restart=on-failure or Restart=on-abnormal as recommended choices for long-running services in its NEWS guidance, but the exact behaviour should be checked against the systemd version installed on your VPS.

RestartSec introduces a delay before the next launch. A delay gives a transient network problem time to clear and keeps a failed process from cycling as quickly as it can. The example uses fifteen seconds only as a starting point for testing, not as a universal value. A longer delay may be more sensible when the input or network is slow to become available.

A restart policy is not a retry policy for every possible error. If the stream key is wrong, FFmpeg may fail on every attempt. If the input path is wrong, restarting merely repeats the same error. If a VPS has lost outbound network access, repeated launches do not fix that condition. Read the first failure carefully before increasing the restart frequency.

Also consider systemd's start-rate limiting. If a service fails repeatedly, systemd may eventually mark it failed instead of continuing to start it. This is useful protection against a rapid failure loop, but it can surprise you during testing. Check the local manual for StartLimitIntervalSec and StartLimitBurst, and choose values that distinguish a temporary outage from a command that can never succeed.

Do not use Restart=always as a substitute for understanding the command. It can restart after a clean exit, which may be useful for a particular playlist design, but it can also conceal an input that ends immediately or a wrapper that is returning too soon. Decide whether an intentional stop should remain stopped.

For a 24/7 channel, the desired behaviour is usually straightforward: a normal service stop stays stopped, an unexpected FFmpeg failure receives a delayed restart, and repeated failures become visible in the journal. Write that policy down before testing so that an automatic restart does not turn an obvious configuration error into an overnight stream of repeated error messages.

Consider FIFO recovery for transient output errors

FFmpeg's FIFO muxer has recovery-related controls including attempt_recovery and recovery_wait_time. These belong to the output configuration and can attempt recovery from certain transient output errors while FFmpeg remains running. Read the FFmpeg documentation for the installed build and the exact muxer arrangement before adding them.

This is not the same as adding a generic reconnect flag to any command. FFmpeg has separate options for different protocols and directions, and an option that helps an input connection does not automatically make RTMP or RTMPS publishing recoverable. The FFmpeg protocols reference explains the protocol-specific scope; check the version on your VPS rather than copying an option from an unrelated example.

A FIFO recovery configuration is appropriate only when the selected output path supports it and when you understand what happens during the wait. The process may continue running while recovery is attempted. That can prevent systemd from taking over, which is exactly why you must monitor both the process and the output result.

If the output error is permanent, in-process recovery may keep trying without producing a usable stream. If FFmpeg exits instead, systemd's restart policy is the relevant control. You can use both layers, but keep their responsibilities clear: FIFO recovery addresses a supported output failure inside FFmpeg; systemd handles the lifetime of the FFmpeg process.

After adding output recovery, test the actual failure mode. Do not infer success from the absence of an immediate exit. Check whether FFmpeg logs a recovered output, whether YouTube's health state changes, and whether the viewer-facing playback returns. A recovery attempt can be technically successful at one layer while the ingest session still needs attention at another.

Keep stream credentials out of exposed files and logs

A YouTube stream key should be treated as a secret. Do not place a working key in a blog-style unit example, a screenshot, a public repository, a broadly readable shell history, or a pasted support log. If it has been exposed, rotate it in YouTube Studio and update the service using the new value.

Keep the key in a root-owned or otherwise tightly restricted environment file, credentials mechanism, or protected wrapper arrangement. The exact choice depends on the operating system and your access model. Ensure that the service account can read what it needs without making the file readable to every local user.

For example, the wrapper can read a protected variable such as YOUTUBE_STREAM_KEY and construct the destination URL at runtime, while the unit file contains no actual key:

#./bin/sh
exec /usr/bin/ffmpeg \
  -re -stream_loop -1 -i /srv/video/channel.mp4 \
  -c:v libx264 -c:a aac \
  -f flv "rtmps://example.invalid/live/${YOUTUBE_STREAM_KEY}"

The hostname above is deliberately not a working ingest address, and no real credential belongs in this article. Use the current destination details shown by YouTube for your channel. Make sure the wrapper does not echo the expanded command before execution.

Be careful with logging. FFmpeg may print a destination URL or an error containing part of it, depending on how the command is assembled. Review the journal after the first launch and redact any exposed credential before sharing logs. A stream key that appears in a command-line listing, a process inspection result, or a diagnostic bundle should be considered exposed.

YouTube recommends RTMPS for live ingest. Its current encoder settings guidance also recommends a two-second keyframe frequency and says not to exceed four seconds. Follow the current page for the codec, resolution, frame rate, audio settings, and bitrate that match your stream. Do not copy one bitrate to every channel, because YouTube's recommended ranges depend on those other settings.

Check service logs and YouTube stream health

Start with the service manager, then the journal. Useful checks include:

sudo systemctl is-active youtube-stream.service
sudo systemctl status youtube-stream.service
sudo journalctl -u youtube-stream.service --since "today"

The exact time filter is optional. During a live incident, narrow the journal to the period around the failure. Look for the FFmpeg exit message, the reason for an output error, whether the service restarted, and whether the same error appeared on every attempt.

A service shown as active means that the configured process is running. It does not prove that frames are arriving at YouTube. FFmpeg can remain active while an output path is failing, and a newly restarted process can be active while using a bad input, invalid credentials, or unsuitable encoder settings.

Then open YouTube Live Control Room and check the stream health messages and preview. Confirm that the expected video and audio are present, not merely that a connection appears. Check live playback from a viewer's perspective as well, because the control room and public playback answer different questions.

For a channel built around a long playlist, monitoring the content matters too. An encoder can be healthy while the wrong file is playing, the image is frozen, or audio has disappeared. This is why a restart test should include representative motion and audio rather than a static test frame only.

If you are designing the whole channel rather than repairing one service, compare the recovery plan with the content plan in how to make a 24/7 YouTube live stream from pre-recorded videos. The more unattended the channel is, the more useful it becomes to separate “the process is running” from “the audience is receiving the intended programme”.

When the recurring problem is the VPS itself, rather than FFmpeg, record the host's reboot history, network events, disk space, CPU load, and available outbound bandwidth. Do not attribute a provider's uptime, bandwidth policy, or support behaviour to the service unit. Those are separate hosting questions that must be checked with the provider's current documentation.

For operators who do not want to maintain a VPS process, StreamNeo removes the need to keep a local FFmpeg service alive by accepting the uploaded video and YouTube stream key, then running and monitoring the broadcast remotely with automatic restart handling. It remains important to check YouTube's event and playback state after a recovery; no process supervisor should be treated as a continuity guarantee.

Test process exits and output errors

Test the process-exit path first, because it is the clearest systemd scenario. Use a non-production stream or a suitable maintenance window. Start the service, confirm that YouTube is receiving the expected content, and then stop the FFmpeg process in a controlled way that represents an unexpected exit. Watch the service status and journal to confirm that systemd records the failure and launches a new process after the configured delay.

Do not assume the new process has resumed the same media position. If the command starts a single file from its beginning, the new process will follow that command. If it loops a file or playlist, it will follow the loop logic you configured. Check what YouTube displays after the restart and note whether the live event remains available, changes state, or requires operator action.

Then test an output-side problem. You might use an isolated test destination or a controlled network interruption, but do not deliberately damage a production channel without a recovery plan. The aim is to learn whether FFmpeg remains running, whether its FIFO recovery controls are actually supported by the selected output, and whether systemd therefore does or does not intervene.

Record the result in three columns: what happened to FFmpeg, what systemd did, and what YouTube showed. This simple record prevents a common mistake in which a successful process restart is reported as a successful stream recovery even though the viewer-facing result was different.

Test a persistent failure as well. Temporarily use an invalid input path or another safe test condition, then observe whether the service enters a repeated restart loop, reaches the configured start limit, or remains active with a failing output. Restore the valid configuration and confirm that the service can recover from the deliberate test.

Before leaving the channel unattended, verify the following:

  • The unit starts after a VPS reboot.
  • FFmpeg runs in the foreground under the intended service account.
  • An unexpected process exit produces a delayed restart.
  • Repeated failures are visible rather than silently cycling.
  • The stream key is not present in shared files or routine logs.
  • YouTube shows the expected video, audio, and stream health after recovery.
  • Your documentation states what an operator must check when YouTube does not resume normally.

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

Will systemd restore the same YouTube live event after FFmpeg exits?

Not necessarily. systemd starts the command again, while YouTube decides how the ingest connection and live event are handled. Check Live Control Room and public playback after the restart rather than assuming that the original event or viewer session has continued.

Should I use FFmpeg recovery options instead of systemd?

They address different failure layers. FIFO recovery may handle supported transient output errors while FFmpeg remains running; systemd can relaunch FFmpeg after the process exits. Use the installed FFmpeg documentation and test the selected output path before relying on either behaviour.

Why is my service active but YouTube shows no useful stream?

The process may be alive while the output is failing, the credentials are rejected, the input is invalid, or the encoder settings do not suit the ingest path. Inspect the journal, then check YouTube's stream health, preview, and viewer-facing playback.

Does a restart continue from the same point in the video?

No automatic continuity should be assumed. A new FFmpeg process follows the input and loop instructions in its command, which may mean starting a file or playlist again. If the input position matters, test and document the exact behaviour of your command rather than promising seamless resumption.

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 Troubleshooting guides ↗ · All topics ↗