A Raspberry Pi can start an FFmpeg YouTube stream automatically after power returns if you run the command as a systemd service and enable that service at boot. The important part is not a special YouTube command, but preserving the exact command, paths, permissions and environment that already work manually.
This arrangement handles a Pi restarting after a power cut. It does not, by itself, recover every camera, network, credential or YouTube broadcast failure. You need to test the service after a real reboot and check YouTube’s own stream health rather than treating a running Linux process as proof that viewers are receiving a good feed.
Confirm the FFmpeg command works manually
Do not begin by writing a unit file. First establish that the complete FFmpeg command works when you launch it yourself on the Pi. The input might be a USB camera, a Raspberry Pi camera, a video file, an audio source or a script that produces frames. The systemd service must reproduce that working arrangement.
A typical command has four parts: the input, any scaling or filtering, the video and audio encoders, and the YouTube output URL containing the stream key. The exact options depend on your camera, file format, Pi model and installed FFmpeg build, so treat an example as a starting point rather than a universal recipe.
Run the command from the same account that you expect the service to use. Let it send a test feed to YouTube, then inspect both the terminal output and Live Control Room. Stop it only after you have confirmed that the input is valid, the audio is present if required, and YouTube is receiving the feed.
Keep the command in a text file while you test it. Copying a known-working command into a service is safer than trying to improve the encoding settings and automate startup at the same time. If you later change resolution, frame rate, audio or input options, test the command manually again before changing the service.
Do not copy an old raspivid command without checking the current camera software and operating system on your Pi. Camera support and capture methods vary between Raspberry Pi setups. The Raspberry Pi documentation is the appropriate place to confirm the camera configuration for your hardware.
The FFmpeg executable may not be in the same location when launched by a service. Find it with command -v ffmpeg, then use the resulting absolute path, such as /usr/bin/ffmpeg, in the unit. You should also record the absolute path to the input file, playlist, script or device.
If the command is a shell pipeline, remember that systemd does not automatically interpret shell operators such as |, >, && or command substitution in ExecStart. Either put the pipeline in a maintained executable script or explicitly invoke a shell. Calling FFmpeg directly is usually easier to inspect and less prone to quoting mistakes.
Prepare paths, credentials and the service environment
A service starts with a controlled environment, not with the interactive settings you see in your normal terminal. It may have a different PATH, a different home directory and different access to mounted storage. Make those assumptions explicit before you create the unit.
Choose a dedicated account or an existing account that owns the media and can access the input device. Avoid running the stream as root simply because it makes an early test pass. If the camera or media files are readable only by your normal user, either correct the permissions or set the service to run as that user.
Use absolute paths everywhere. For example, /home/pi/stream/start-stream.sh is clearer to systemd than start-stream.sh, and /home/pi/media/darshan.mp4 is safer than darshan.mp4. Set a working directory if the command expects relative files:
WorkingDirectory=/home/pi/stream
Keep the stream key out of the unit file if the file could be copied, backed up or displayed in a support request. YouTube describes the stream key as similar to a password and address for the encoder. Store it in a file with restricted permissions, or use an environment file that only the service account and administrators can read. The YouTube Help guidance on stream keys explains how to reset a key if it is exposed.
For example, an environment file might contain a value used by your script:
YOUTUBE_STREAM_KEY=replace-this-value
Protect it with an appropriate owner and mode, then make the script read it without printing it. Do not put the key in a public Git repository, a screenshot, an issue report or a verbose log. Be aware that command lines can also appear in process listings, so passing a secret as an argument is not always the best arrangement.
Before automating the service, check the things that may not exist immediately after power is restored:
- Is the network interface connected and has it received an address?
- Is the camera present under the expected device path?
- Is the media disk mounted before FFmpeg starts?
- Does the service account have access to the input and output files?
- Are the required environment variables available?
- Is the clock sufficiently correct for the software and connection to behave normally?
A Pi may boot faster than a wireless network, USB camera or external storage. The service therefore needs deliberate ordering and retry behaviour. There is no single dependency setting that suits every camera and storage arrangement, so validate the result on the actual device.
Create a systemd unit for the stream
Create a unit such as /etc/systemd/system/youtube-stream.service. You will need administrator access to write there. A minimal direct-FFmpeg pattern looks like this:
[Unit]
Description=FFmpeg YouTube stream
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/stream
ExecStart=/usr/bin/ffmpeg -i /home/pi/media/input.mp4 -c:v libx264 -preset veryfast -b:v 6M -maxrate 6M -bufsize 12M -g 60 -c:a aac -b:a 128k -f flv "rtmps://example-output-url/STREAM_KEY"
Restart=on-failure
RestartSec=15
[Install]
WantedBy=multi-user.target
This is a pattern, not a command to paste unchanged. Replace the user, paths, input, output URL and encoding settings with the command that you have already tested. The -g 60 value shown here assumes a particular frame-rate and keyframe choice; it is not a universal recommendation. Match the keyframe interval to the frame rate and YouTube’s current encoder guidance.
Wants=network-online.target and After=network-online.target express that the service should be started with the network-online target and ordered after it. They do not prove that your router has working internet access, that DNS works, or that the YouTube ingest endpoint is reachable. A service can still start while the wider connection is unusable.
Restart=on-failure asks systemd to start the process again when it exits unsuccessfully. RestartSec=15 prevents an immediate tight loop. Choose a delay that gives the camera, storage and network time to become ready. If FFmpeg exits repeatedly, read the journal before increasing the restart behaviour. A restart policy cannot repair a missing camera, invalid stream key or broken command.
If you use a script, make it executable and keep the script’s paths explicit. The unit then becomes easier to read:
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/stream
ExecStart=/home/pi/stream/start-stream.sh
Restart=on-failure
RestartSec=15
The script should use exec for the final FFmpeg command where practical, so the FFmpeg process remains the main service process and its exit status is visible to systemd. Log important setup failures to standard output or standard error rather than hiding them in a file whose location you may forget.
If the input is a mounted disk or a camera device, add only dependencies that reflect your real arrangement. For example, a mount may need its own systemd mount unit or an explicit mount relationship. Do not add arbitrary delays and assume they solve every boot race. A delayed start may appear to work on one reboot and fail on another.
The community YouTube-Pi4-StreamMachine project demonstrates the general idea of installing FFmpeg and using a systemd service on a Raspberry Pi. It is useful as a reference for the boot pattern, but its capture command and service details are project-specific. Your unit still has to match your own input and operating system.
Enable the service at boot
After saving the unit, ask systemd to reload its unit definitions:
sudo systemctl daemon-reload
Start it manually through systemd before testing a reboot:
sudo systemctl start youtube-stream.service
Then inspect it:
systemctl status youtube-stream.service
If the service runs and YouTube receives a healthy preview, enable it for future boots:
sudo systemctl enable youtube-stream.service
Enabling and starting are different actions. start launches the service now. enable creates the boot-time relationship so that systemd will request it during later boots. You can use sudo systemctl enable --now youtube-stream.service after the unit has passed its manual test, but keeping the two actions separate makes the sequence easier to understand.
Check that systemd accepted the unit without a syntax error. If you edit the file, run daemon-reload again. If you change the command while the service is running, restart it deliberately:
sudo systemctl daemon-reload
sudo systemctl restart youtube-stream.service
Do not assume that enabling the unit means the stream is now unattended. The first useful test is a controlled reboot with the monitor or another access method available. The second is a power-loss test when you can safely perform one. A normal shutdown tests boot ordering; an abrupt power cut also exposes storage and hardware issues that systemd cannot correct.
For a broader comparison of always-on arrangements, the practical concerns in running a 24/7 YouTube stream from a laptop with the lid closed are relevant here too: power, network access, heat, storage and what happens when the host is unavailable.
Check status and logs after reboot
After the Pi comes back, wait for the system to settle and inspect the service:
systemctl status youtube-stream.service --no-pager
For the complete service journal, use:
journalctl -u youtube-stream.service --no-pager
To watch new messages while the service is running:
journalctl -u youtube-stream.service -f
A healthy status should show that the unit is active and running, but that is only the first layer of the check. Read the FFmpeg messages as well. They may show that the input cannot be opened, the output connection was refused, the stream key was rejected, the file ended, the audio device disappeared or the process is repeatedly restarting.
The most useful diagnostic question is whether the service failed to launch or FFmpeg launched and then failed. If there is no recent service entry, check the unit name, enablement and syntax. If the journal contains FFmpeg errors, check the executable path, input path, permissions, camera device, environment file and network connection.
Useful checks include:
systemctl is-enabled youtube-stream.service
systemctl is-active youtube-stream.service
command -v ffmpeg
ip addr
Use systemctl cat youtube-stream.service to confirm which unit systemd is actually reading. This can reveal that you edited a different file, used a different service name or left an older command in place.
A service that keeps restarting deserves attention rather than a larger restart policy. Look at the timestamps in the journal. If the process exits as soon as it starts, the command or input is usually the first place to look. If it works for a while and then exits, investigate the input, storage, temperature, connection and YouTube response. Systemd can repeat the attempt, but it cannot determine whether the underlying fault has gone away.
For recorded loops, also confirm what happens when the file reaches its end. An FFmpeg process that exits cleanly after one file may not be treated as a failure by Restart=on-failure. If you need continuous playback, use a tested looping command or a maintained script and verify its behaviour manually before placing it under systemd. The guide to keeping a YouTube gaming rerun stream running when the playlist ends covers the related problem of content ending while the channel is expected to continue.
Verify the feed in YouTube Live Control Room
Linux status is not the final test. Open YouTube Live Control Room and check that the intended broadcast receives a preview, has the expected audio and picture, and reports acceptable stream health. A process can remain active while sending frozen frames, no audio, an invalid input or no usable data at all.
YouTube’s encoder guidance covers RTMP and RTMPS delivery, supported video codecs, audio codecs, frame rates, keyframes and bitrate. YouTube says, “We recommend streaming to YouTube Live with RTMPS, a secure extension to the popular RTMP streaming video protocol.” Read the current YouTube encoder settings guidance before choosing the output settings.
For H.264, YouTube’s listed recommended bitrates include the following. These are ingestion recommendations from YouTube, not Raspberry Pi performance benchmarks:
| Target | YouTube-listed H.264 bitrate | Practical check |
|---|---|---|
| 720p at 30 fps | 6 Mbps | Confirm the Pi and connection sustain the rate continuously |
| 720p at 60 fps | 8 Mbps | Check that the selected encoder can maintain the higher frame rate |
| 1080p at 30 fps | 14 Mbps | Leave upload capacity beyond the stream bitrate |
| 1080p at 60 fps | 17 Mbps | Test the complete capture and encoding path before relying on it |
YouTube recommends a two-second keyframe interval and says not to exceed four seconds. It also advises leaving 20% upload headroom beyond the total stream bitrate. That headroom is not a guarantee against an unstable connection. A household connection shared with other users, a weak wireless link or an unreliable route to the ingest service can still interrupt the broadcast.
Test with audio and movement similar to the real channel. A devotional video with continuous music, a static ambience scene and a camera pointed at a live location put different demands on the input and encoder. Watch the preview after boot rather than checking only that the title of the broadcast remains present.
If you stream from India over a connection with a limited data allowance, compare the chosen bitrate with the full-day data use before committing to a resolution. The guide to reducing data usage for an OBS 24/7 YouTube stream in India discusses the same trade-off from a different host setup. Lowering bitrate can reduce data use, but it must remain compatible with the picture quality and YouTube’s recommended settings for your chosen output.
Plan recovery beyond host restarts
A boot service solves one failure class: the Pi went down and later booted again. It does not automatically solve every other failure class.
A camera may stop responding while the operating system remains up. A USB device may reconnect under a different path. A media disk may fail to mount. Wi-Fi may be associated with the router but unable to reach the internet. A stream key may be revoked or reset. YouTube may stop accepting the broadcast, or the encoder may continue running while producing unusable output.
Treat each as a separate condition. For the camera, check whether the capture device exists and whether the capture command can reopen it. For storage, check mounts and file permissions. For networking, check local connectivity, DNS and the route to the ingest endpoint. For YouTube, inspect Live Control Room and confirm that the stream key and selected broadcast are still correct.
A simple restart policy is useful, but repeated restarts should produce evidence in the journal. Consider a separate health-check design only after you can define what “healthy” means and how to respond safely. A process check alone is weak: FFmpeg can be running while the output is stalled. A check that restarts the service too aggressively can create an avoidable loop.
Keep a written recovery procedure beside the Pi. It should include the service name, the location of the tested command, how to view the journal, where the protected key is stored, how to test the camera and how to confirm the feed in YouTube. This is more durable than relying on memory after an overnight interruption.
If you do not need the Pi to capture a live camera or encode locally, a cloud-based arrangement can remove the need to keep this particular computer powered and connected. StreamNeo removes the repeated local startup work for an uploaded video by letting you provide the file and YouTube stream key once, then running the YouTube broadcast while your computer is off. It is still not a promise that every YouTube or source-side fault will recover automatically, so you should verify the channel and stream health.
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 enabling systemd guarantee that my stream returns after a power cut?
No. It makes systemd request the service during the next boot. The camera, storage, credentials, network and YouTube ingest must still be available, and FFmpeg must still be able to produce a valid stream.
Why is the service active when YouTube shows no healthy feed?
active describes the service process from systemd’s perspective. It does not prove that FFmpeg is receiving valid input or that YouTube is accepting usable video and audio. Read journalctl -u youtube-stream.service and inspect the stream in Live Control Room.
Should I put the YouTube stream key directly in the unit file?
Avoid doing so when the unit might be copied, backed up or shared. Keep the key in a restricted environment file or another protected configuration method, and reset it through YouTube if it is exposed.
Is a Raspberry Pi 4 sufficient for every FFmpeg YouTube stream?
There is no universal answer. The input type, resolution, frame rate, codec, audio and bitrate all affect the workload, and the available guidance does not establish a general Pi performance benchmark. Test the exact command on the exact hardware and monitor both the service and YouTube feed after a reboot.