A disconnected FFmpeg process can sometimes recover a temporary HTTP interruption by retrying the same input connection. If the process exits, systemd can start it again, but neither layer automatically restores YouTube’s event, the input position or every viewer’s playback.
The reliable approach is to separate those jobs. Use FFmpeg’s HTTP reconnect options for a live connection that may return, and use a systemd restart policy for a process that has stopped. Then check what happened to the source and YouTube event before treating the channel as recovered.
Identify which layer failed
Start with the error rather than adding every reconnect flag to the command. A brief network reset, an HTTP end-of-file condition, an expired media URL and an ended YouTube event are different failures. They may all look like a frozen or disconnected stream from the viewer’s side, but they need different recovery actions.
There are two main layers to distinguish:
| Failure | What FFmpeg can attempt | What needs a separate action |
|---|---|---|
| Temporary interruption while the same HTTP input remains valid | Reconnect the input and continue trying | Check whether the source really returns |
| EOF from an input expected to remain live | Treat EOF as retryable with -reconnect_at_eof 1 |
Confirm that EOF was not the genuine end of the source |
| Expired or unusable media URL | Repeatedly retrying the old URL | Run extraction again and obtain a current URL |
| FFmpeg exits | Nothing inside the stopped process | Let a supervisor start a new process |
| YouTube event ends or changes state | No guarantee from FFmpeg’s input reconnect | Inspect the event and decide whether to resume or create another one |
The FFmpeg protocol options discussed here apply to HTTP input. They are not universal reconnect switches for every input protocol. Put them before the -i they configure, especially if your command has more than one input.
Read both stderr and the exit status. A connection reset suggests a transport problem. An HTTP rejection, authentication failure, unavailable live event or extractor error suggests that the URL or session needs to be reacquired. Keeping those messages in a log is more useful than seeing only that the service restarted.
If you are building a channel from a file rather than relaying another live source, first decide whether a continuous loop is the right design. The explanation in what happens to a live stream when power or internet goes out is useful here because it separates local playback from the broadcast’s state on YouTube.
Create a systemd service for FFmpeg
A systemd service gives FFmpeg a defined command, environment and log destination. It also gives the operating system something to supervise after the terminal session closes. This is different from FFmpeg’s own reconnect handling: systemd only acts when the process starts, stops or exits.
Create a dedicated service file, for example /etc/systemd/system/youtube-relay.service:
[Unit]
Description=YouTube FFmpeg relay
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=stream
WorkingDirectory=/home/stream
ExecStart=/usr/bin/ffmpeg -reconnect 1 -reconnect_streamed 1 -reconnect_at_eof 1 -reconnect_delay_max 30 -reconnect_max_retries 100 -i https://example.invalid/input -c copy -f flv rtmp://a.rtmp.youtube.com/live2/STREAM_KEY
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Replace the example input and output with your own command. Do not paste a real stream key into an article, shell history shared with other users or a public issue. A key is an access credential for the broadcast destination, so store it with suitable permissions or provide it through a protected environment file where practical.
The User must be able to read the input, execute FFmpeg and access any files used by the command. If the service loops a local video, use an absolute path or a WorkingDirectory that makes the path unambiguous. A command that works in your interactive shell may fail under systemd because it has a different PATH, home directory and environment.
After saving the file, ask systemd to read it and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now youtube-relay.service
sudo systemctl status youtube-relay.service
Use journalctl for the detailed output:
sudo journalctl -u youtube-relay.service -f
Do not assume that an active (running) status means viewers are receiving useful content. It means the process is running. YouTube may still reject the output, the source may be producing no usable frames, or the event may be in a state that needs attention.
For a permanent 24/7 file loop, a local systemd service is only one part of the operating decision. If the main concern is keeping a home computer powered and connected overnight, compare it with 24/7 loop services and relay tools by looking at who is responsible for the source file, the broadcast connection and the restart process.
Configure a failure restart policy
Restart=on-failure tells systemd to restart the service when the process exits unsuccessfully, is terminated by a signal or hits another failure condition. It does not restart a process that is still alive but has stopped producing useful output. It also does not know whether the YouTube event is healthy unless the process itself exits or an additional health check acts on that information.
A short delay prevents an immediate crash from producing a tight restart loop. RestartSec=10 is only a starting choice, not a universal value. Choose a delay that allows a temporary network condition or dependency to settle without leaving the channel unattended for an unnecessarily long period.
For a stricter operating policy, add a service-level start limit. For example:
StartLimitIntervalSec=300
StartLimitBurst=5
These settings limit repeated starts within a time window. They are useful when a bad URL, invalid key or broken command would otherwise restart indefinitely and fill the journal. The trade-off is that a service can eventually stop trying, so you need a notification or a check that tells you when the limit has been reached.
You can also use Restart=always, but understand the difference. It asks systemd to restart after a clean exit as well as after a failure. That may be suitable for a process intended to run continuously, but it can hide a genuine end-of-input condition. With on-failure, a clean exit remains visible as a reason to inspect the job.
Keep the policy bounded at more than one level. FFmpeg’s input retries should have a maximum delay and retry count. systemd should have a sensible restart delay and, where appropriate, a start limit. The purpose is not to create an endless loop that conceals a permanent problem. It is to give temporary failures room to recover while making repeated failure visible.
A restart also starts the command from the beginning of its configured input. If that input is a file, the output may begin a new segment or a new broadcast session depending on the command. If it is a live source, the new process may need a newly obtained URL. Do not describe this as seamless continuation unless you have verified the complete path, including YouTube and the viewer experience.
Consider FFmpeg’s FIFO muxer recovery
FFmpeg also has a FIFO muxer designed to buffer output and handle some transient output-side failures. This is a different recovery layer from HTTP input reconnects and from systemd supervision. It can be relevant when the output connection temporarily fails but the FFmpeg process remains alive.
A typical pattern looks like this in principle:
ffmpeg -i "$INPUT" -c copy \
-f fifo \
-fifo_format flv \
-map 0 \
-drop_pkts_on_overflow 0 \
"fifo:rtmp://a.rtmp.youtube.com/live2/STREAM_KEY"
Treat this as a configuration area to verify against the FFmpeg build and documentation, not as a universal recipe. The FIFO muxer has its own options and behaviour, and the right settings depend on whether the output is a live relay, a recording or another workflow. Consult the FFmpeg protocol and format documentation for the options supported by the version installed on your machine.
The important distinction is direction. HTTP reconnect flags are input-side options placed before the relevant -i. FIFO handling concerns output delivery. systemd concerns the lifetime of the FFmpeg process. Combining them may address different failure modes, but adding all three does not turn a fragile source or a closed YouTube event into a guaranteed continuous broadcast.
FIFO buffering also involves trade-offs. More tolerance for a short output interruption can mean more delay or buffered data. If the process cannot recover the output, the FIFO layer may eventually report an error rather than repairing the underlying destination. If the source itself has ended or its URL has expired, output buffering cannot solve that input problem.
For a YouTube input obtained through an extractor, make the extraction step explicit. The yt-dlp documentation describes livestream options and passing downloader-specific arguments to FFmpeg. Its ffmpeg_i arguments can be useful for input reconnect settings, but inspect the installed version with yt-dlp --help and keep verbose logs. --live-from-start controls where a livestream download begins; it is not a general reconnect switch.
A direct pattern for an HTTP input is:
ffmpeg \
-reconnect 1 \
-reconnect_streamed 1 \
-reconnect_at_eof 1 \
-reconnect_delay_max 30 \
-reconnect_max_retries 100 \
-i "$INPUT_URL" \
-c copy output.mkv
The flags must be scoped to the input they are intended to configure. This pattern retries the current HTTP URL. It does not prove that FFmpeg can refresh a YouTube media URL or repeat the extraction process after the session expires.
Test process-exit recovery
Test the supervisor deliberately before relying on it overnight. First start the service and confirm that the expected FFmpeg command appears in systemctl status. Then stop the process in a controlled way and watch whether systemd records the exit and starts a new instance.
For example, identify the process through the service rather than killing an unrelated FFmpeg job:
sudo systemctl status youtube-relay.service
sudo systemctl restart youtube-relay.service
sudo journalctl -u youtube-relay.service --since "10 minutes ago"
A restart command tests whether systemd can launch the service, but it does not test a crash path. A separate maintenance window can test failure handling by stopping the main process and confirming that Restart=on-failure behaves as intended. Do not perform that test during a broadcast you cannot afford to interrupt.
Check these points in the journal:
- The old process ended and the new process started.
- The new process used the expected input and output arguments.
- The service account could read the source and access any required files.
- The retry delay was applied rather than causing rapid repeated starts.
- A permanent error remained visible instead of being mistaken for recovery.
If the command is wrapped in a shell script, decide how the script returns FFmpeg’s exit status. A wrapper that keeps running after FFmpeg fails can make systemd believe the service is healthy. Conversely, a wrapper that exits immediately on an expected condition may trigger restarts more often than you intend.
Also test a temporary input interruption if you can do so safely. A process that stays running while FFmpeg retries is a different result from a process that exits and is restarted. Record the timestamps and read the logs; the viewer-facing result may include a gap even when the process eventually resumes.
Check the event and input after restart
A new FFmpeg process does not automatically know what happened to the previous YouTube event. Depending on your command and source, it may reconnect to an existing event, publish to a destination that now rejects the connection, or start sending from the beginning of a file. You must check the event’s state in YouTube Studio and confirm that the intended stream is receiving data.
The input position is another separate question. A local file normally starts at the position selected by the new command. A live HTTP source may resume at a point chosen by the source, or it may return a different point after reconnecting. With an expired media URL, retrying the same URL can simply repeat the same error.
When the source comes from a YouTube watch URL through an extractor, separate URL acquisition from FFmpeg. The extractor may need to run again to obtain a current media URL. This is why a supervisor around the extractor-plus-FFmpeg workflow can be more appropriate than placing reconnect flags only inside FFmpeg. It is still not a guarantee that a new process will restore the same event or viewer position.
Viewer playback is separate again. Some viewers may buffer and continue, while others may see an interruption, reload or a changed live point. A process restart cannot force every player to retain its previous state. If continuity matters, observe the public watch page from a separate connection and compare it with the local journal and YouTube Studio status.
For a channel that uses scheduled or recurring material, document what should happen after recovery. Should the file start again, should a new segment be created, should the live event be ended and recreated, or should someone intervene? A written decision prevents an automatic restart from quietly producing the wrong content. If you are testing privately, run the live stream as an unlisted test event before changing a public channel.
Monitor the VPS service
A restart policy is not monitoring. Check the service state, recent journal entries, process age and destination health. A simple periodic check can alert you when the unit is inactive, restarting repeatedly or running without recent useful FFmpeg output.
Useful commands include:
systemctl is-active youtube-relay.service
systemctl show youtube-relay.service -p NRestarts -p ExecMainStatus -p ActiveEnterTimestamp
journalctl -u youtube-relay.service --since "1 hour ago" --no-pager
The exact fields available depend on your systemd version. Treat them as clues, not as proof that YouTube viewers have an uninterrupted picture. Pair them with an observation of the YouTube event and, where possible, a separate viewer connection.
Keep logs long enough to answer a practical question: did FFmpeg reconnect inside one process, or did systemd launch a new process? Include the input URL acquisition step in the record without logging secrets. If the same HTTP error repeats, escalating the retry count is unlikely to help until you establish whether the URL is still valid.
Set an alert for the conditions that matter to you: the service is inactive, the restart count keeps rising, the start limit is reached, or no expected output has appeared for a defined period. Avoid alerts that fire on every ordinary reconnect unless someone can act on them. The goal is to distinguish a short interruption from a job that needs a fresh URL, a new event or manual inspection.
If managing a VPS becomes more work than the channel itself, a file-based workflow can remove a particular operational burden: StreamNeo lets you upload the video once, provide the YouTube stream key, and have the cloud-run broadcast monitored and restarted without leaving your computer switched on. That does not remove the need to check YouTube’s event and content requirements, but it avoids maintaining this FFmpeg service for a straightforward uploaded loop.
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
Do FFmpeg reconnect flags recover every YouTube disconnection?
No. They are intended for supported input connection failures, particularly HTTP interruptions, and they retry the current URL. They do not guarantee a fresh YouTube media URL, a live event that has ended, or uninterrupted viewer playback.
Does systemd continue from the point where FFmpeg stopped?
Not by itself. systemd starts the configured command again, so a file may begin from its configured starting position and a live source may acquire a different point or URL. Check the input, event state and public watch page after the restart.
Should I use FIFO, systemd or both?
They address different layers. FIFO can handle some output-side interruptions while FFmpeg remains alive, systemd can restart a process that exits, and HTTP reconnect options handle certain input interruptions. Use only the layers that match your failure modes, then test their combined behaviour.
Why does the service restart but the stream remain offline?
The process may be running while the URL is expired, the source has ended, the YouTube event rejects the connection or the command is not producing valid output. Read the FFmpeg error, confirm that the extractor can reacquire the source where applicable, and inspect the event in YouTube Studio rather than relying on the systemd status alone.