If you want FFmpeg to keep sending a YouTube live stream after you disconnect from SSH or the VPS reboots, run it as a systemd service. systemd can start the process at boot, run it under a dedicated account, restart it after failures and collect its logs.
That does not make the broadcast healthy by itself. You must test the FFmpeg command first, then check both the service logs and YouTube Studio’s preview and stream health. A service can be active (running) while YouTube is receiving no usable video, the wrong broadcast or no broadcast at all.
Prepare the FFmpeg command before using systemd
Do not begin with a unit file. First make the exact FFmpeg command work in a controlled SSH session, using the same input file, output settings, ingest endpoint and service account that the final service will use.
Confirm four things during this test:
- FFmpeg can read the source media.
- The output contains the intended video and audio tracks.
- The codec, frame size, frame rate, bitrate and keyframe interval match the current YouTube guidance.
- YouTube Studio shows the incoming stream and provides a healthy preview.
The FFmpeg documentation explains the general input, filtering, encoding and output structure, but there is no single command that is correct for every VPS, source file or channel. A pre-encoded file may be suitable for stream copying in some cases. A file with an unsuitable codec, variable timing or missing audio may need to be re-encoded. A live input URL has different failure modes from a local looping file.
For a file-based channel, decide whether the content should loop. Use real-time output rather than sending the entire file as quickly as the VPS can read it, and ensure the loop behaviour matches the editorial purpose. A devotional channel, product demonstration and ambient station may each need different handling for transitions, silence, audio continuity and end-of-file behaviour.
Keep the command in a private working file while testing, but do not place the real stream key in a script that might later be copied to a repository or shared with another administrator. The command should use the YouTube ingest URL and key supplied by the selected broadcast in YouTube Studio. Prefer RTMPS where your workflow supports it. YouTube Help says, “We recommend streaming to YouTube Live with RTMPS, a secure extension to the popular RTMP video protocol.” See YouTube’s current live encoder settings and bitrate guidance before choosing values.
YouTube’s H.264 recommendations listed on that page include 17 Mbps for 1080p at 60 fps, 14 Mbps for 1080p at 30 fps, 8 Mbps for 720p at 60 fps, 5 Mbps for 720p at 30 fps, 4 Mbps for 480p at 30 fps and 1.5 Mbps for 360p at 30 fps. These are YouTube figures from the page accessed in October 2026, not universal requirements. The complete table also varies by codec, resolution and frame rate. YouTube recommends CBR encoding and a two-second keyframe interval, with the interval not exceeding four seconds.
The VPS still needs enough CPU for the chosen encoding work and enough sustained outbound capacity for the selected bitrate, with room for normal variation. Test the route and source under conditions that resemble the intended broadcast. Do not infer that an Indian VPS is suitable merely because it is located in India, and do not treat a provider’s advertised port speed as proof that your stream will remain healthy overnight.
Create a dedicated unprivileged account
A service that only reads media and sends an outbound stream should not run as root. Create a separate account for the encoder, and give it access only to the files and directories it needs.
On a Debian or Ubuntu-style VPS, an administrator could create a system account and a private working directory like this:
sudo useradd --system --home-dir /var/lib/youtube-ffmpeg --create-home --shell /usr/sbin/nologin ytstream
sudo install -d -o ytstream -g ytstream -m 0750 /var/lib/youtube-ffmpeg/media
Check the commands and account options against your distribution before running them. The important properties are that the account has no interactive login, owns its working directory and can read the intended media. If the source file is elsewhere, grant narrowly scoped read access rather than making the whole media tree world-readable.
For example, a source directory could be owned by a separate content account and shared through a group with read and directory-traverse permissions. Avoid changing ownership of unrelated application files simply to make FFmpeg start. The service should fail clearly when its input is unavailable, rather than silently gaining broad access.
Test as the service account, not only as your administrator account. A command that works in your SSH session may fail under systemd because the service has a different home directory, PATH, current directory, permissions and environment.
sudo -u ytstream test -r /var/lib/youtube-ffmpeg/media/channel.mp4
sudo -u ytstream /usr/bin/ffmpeg -version
Use an absolute path for FFmpeg. Find it with the distribution’s package information or command -v ffmpeg, then verify that the binary is the one you intend to run. If you install FFmpeg from a verified build rather than the distribution package, record its location and check its dependencies before putting it into a boot service.
The guide to reducing CPU usage for a 24/7 YouTube stream on a VPS is useful at this stage because encoding settings determine whether a small machine can keep up. Lowering the output resolution or frame rate may be more reliable than repeatedly restarting an overloaded process.
Store the YouTube stream key safely
Treat the stream key like a password. It can be used to send content to the associated live workflow, so do not put it in a public repository, a screenshot, a ticket, a shared shell history or a world-readable unit file. If you believe it has been exposed, rotate it in YouTube Studio before continuing.
One practical arrangement is a root-managed environment file that the ytstream account can read but other ordinary users cannot. Create the directory and file as root:
sudo install -d -o root -g ytstream -m 0750 /etc/ytstream
sudo install -o root -g ytstream -m 0640 /dev/null /etc/ytstream/youtube.env
sudoedit /etc/ytstream/youtube.env
The file can contain values used by the unit, for example:
YOUTUBE_INGEST=rtmps://your-selected-ingest-endpoint/live2
YOUTUBE_KEY=replace-with-the-key-from-youtube-studio
Do not copy that example into production unchanged. Use the endpoint and key for the specific broadcast, and check how your systemd version parses environment files. Keep the file’s ownership and mode narrow:
sudo chown root:ytstream /etc/ytstream/youtube.env
sudo chmod 0640 /etc/ytstream/youtube.env
A key can still appear in process arguments or diagnostic output if the command expands it into the URL. Inspect your logging and process-monitoring practice. Do not paste a complete ingest URL into a public bug report. You should also check whether FFmpeg prints connection details at the selected log level.
The unit file itself should not contain the real key. Environment files are convenient, but they are not a complete secret-management system. If several administrators have root access, they can read the file. That is normally part of the trust model for a single VPS, but it should be understood rather than hidden.
Write the systemd unit with explicit paths
Create a system service under /etc/systemd/system/. Give it a name that identifies the channel, such as ytstream-devotional.service or ytstream-ambient.service.
The following is a template. Replace the media path, output settings and service name with values already tested interactively:
[Unit]
Description=YouTube FFmpeg stream
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ytstream
Group=ytstream
WorkingDirectory=/var/lib/youtube-ffmpeg
EnvironmentFile=/etc/ytstream/youtube.env
ExecStart=/usr/bin/ffmpeg -hide_banner -loglevel info \
-re -stream_loop -1 -i /var/lib/youtube-ffmpeg/media/channel.mp4 \
-c:v libx264 -preset veryfast -b:v 5M -maxrate 5M -bufsize 10M \
-r 30 -g 60 -keyint_min 60 \
-c:a aac -b:a 128k -ar 44100 \
-f flv "${YOUTUBE_INGEST}/${YOUTUBE_KEY}"
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
This is a structure to adapt, not a universal copy-and-paste encoder command. The -stream_loop -1 option is appropriate only when looping the file is intended. The bitrate, frame rate, GOP settings, encoder preset and audio settings must match the media, VPS capacity and current YouTube guidance. If your input is already compatible, re-encoding may waste CPU. If it is not, stream copying may produce an unsuitable output.
The explicit User, Group and WorkingDirectory make the process context predictable. ExecStart uses an absolute FFmpeg path and an absolute media path, so it does not depend on the interactive shell’s PATH or current directory. The environment file keeps the key out of the unit text, while the quoted final argument keeps the ingest URL together as one argument.
Systemd’s environment-file syntax and variable expansion have details that can vary with the host version. Read the local manual with man systemd.service and man systemd.exec, and validate the unit before starting it. Ubuntu’s Noble systemd.service documentation recommends Restart=on-failure for long-running services because it attempts recovery after errors. It does not repair the input, the network route, the key or the YouTube broadcast.
If the unit contains a long ExecStart, keep it as one command with continuation backslashes as shown. Do not add a shell pipeline unless you deliberately run a shell and understand the resulting signal, quoting and exit-status behaviour. A direct FFmpeg process gives systemd a clearer process to supervise.
Enable restart behaviour and start the service
After creating or changing the unit, ask systemd to reload its configuration:
sudo systemctl daemon-reload
sudo systemctl enable ytstream-devotional.service
sudo systemctl start ytstream-devotional.service
Use enable for boot startup and start for the current boot. They are separate actions. If you want to test without enabling boot startup, start the service first and enable it only after the interactive test and log review are complete.
Check the unit immediately:
sudo systemctl status ytstream-devotional.service --no-pager
sudo systemctl is-enabled ytstream-devotional.service
active (running) means that systemd currently sees the main process running. It does not mean YouTube accepted the broadcast or that the media is valid. If FFmpeg exits cleanly because the input ended, Restart=on-failure may not restart it. That is often preferable for a finite job, but a looping channel should be designed so the process does not end at the intended content boundary.
Do not change this to Restart=always without considering the meaning of a clean exit. always also restarts after a successful exit, which may hide an intentional end-of-stream condition. on-failure is a reasonable starting point for a long-running encoder, but the correct policy depends on how your command reports failures and how you want planned stops to behave.
The RestartSec=10 delay prevents an immediate tight restart loop. It is not a repair mechanism. If the key is revoked or the input path is wrong, the process may fail repeatedly until systemd’s start-rate limits are reached. At that point the unit can remain failed even though the restart directive is present. Inspect the status and journal rather than assuming another restart will help.
To stop a service deliberately:
sudo systemctl stop ytstream-devotional.service
To prevent it starting on the next boot:
sudo systemctl disable ytstream-devotional.service
When you change the unit, run daemon-reload, then restart the service. When you change only the environment file, restarting the service is still necessary because the running process keeps its existing environment.
Read systemd logs and YouTube Studio together
The journal tells you what the supervised process is doing. YouTube Studio tells you what the platform is receiving. You need both views.
Start with recent unit messages:
sudo journalctl -u ytstream-devotional.service -n 100 --no-pager
sudo journalctl -u ytstream-devotional.service -f
The first command is useful after a failure. The second follows new output while you test. Look for input-open errors, permission failures, encoder errors, connection failures, reconnect messages and exit codes. If the journal contains the complete stream URL, redact the key before sharing any output.
Then open the selected live broadcast in YouTube Studio. Confirm that the preview shows the expected picture and audio, that the selected ingest endpoint and key belong to this broadcast, and that stream health remains acceptable while the VPS is sending. YouTube recommends testing with representative motion and audio and monitoring stream health during the event. A static test image can conceal problems that appear in the real channel.
Use this sequence when diagnosing a failure:
| What you observe | What it usually narrows down | What to check next |
|---|---|---|
| The unit fails before FFmpeg starts | Service definition or permissions | systemctl status, unit syntax, executable path, account, working directory and environment-file access |
| FFmpeg starts then exits | Input, command or connection problem | Journal error text, media readability, codec settings, endpoint and key |
| FFmpeg restarts repeatedly | An underlying condition remains unresolved | Input path, network route, CPU pressure, key status and systemd start-rate messages |
| The unit is active but Studio has no usable preview | Process supervision is working, but ingest or media is not | Broadcast selection, key, endpoint, video/audio presence, codec, bitrate and stream health |
| Studio reports health warnings while the process stays active | The VPS is sending, but delivery or encoding may be unsuitable | Sustained outbound capacity, CPU load, frame timing, bitrate and current YouTube guidance |
A process restart cannot fix a revoked key, a missing source file, an unsuitable codec, a broken route or a broadcast that has ended upstream. It may help after a temporary process or connection failure, but only if the underlying condition clears. This is why a healthy-looking systemd status is not the same as a healthy live channel.
If the stream keeps disconnecting, compare the journal with YouTube’s health messages before changing several settings at once. The troubleshooting guide for a YouTube live stream that keeps disconnecting can help you separate network, encoding and platform-side symptoms.
Check capacity and plan for a real overnight test
A VPS in India may reduce the distance to your own administration connection, but location alone does not establish that its outbound path, CPU allocation or transfer allowance suits the stream. This research does not verify a particular Indian provider or plan. Check the provider’s current network terms and measure the actual machine you intend to use.
Your configured video bitrate is only part of the operating picture. Audio, protocol overhead, reconnects and other VPS activity add to the requirement. Test sustained outbound transfer above the configured stream rate rather than checking only a short speed-test result. Also watch CPU usage while FFmpeg handles representative motion, not only a quiet still image.
If the VPS cannot encode reliably, lower the workload by changing the source, output resolution, frame rate or encoder settings after checking YouTube’s current table. Do not reduce bitrate blindly if the result produces poor stream health. If you need more than one channel, measure them together because their CPU and network demands can overlap.
Keep a small operational record: the tested command, source path, service name, FFmpeg path, selected YouTube settings and the date you last checked the official guidance. This makes a later reboot or key rotation less error-prone. Store the record without the secret itself.
For channels built around long media loops, content design matters as well as process supervision. The article on whether 24/7 ambient streams need a playlist covers a related decision about how viewers encounter repeated content. If your goal is a devotional station, compare the media and rights workflow with the setup for a 24/7 Sikh devotional music stream before treating the VPS as the whole solution.
If maintaining the VPS, packages, credentials, input files and monitoring is more work than you want for a single YouTube channel, StreamNeo removes the need to keep an FFmpeg process running on your own VPS: you upload the video once, provide the YouTube stream key and let the hosted stream run while your computer is off, with automatic monitoring and restarts.
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 run FFmpeg as a systemd service?
Test the command interactively first, then place a unit under /etc/systemd/system/ with an explicit FFmpeg path, User=, Group=, WorkingDirectory= and ExecStart=. Reload systemd, enable the unit for boot and start it. Confirm the process in systemctl status, then confirm the actual broadcast in YouTube Studio.
How can I keep a YouTube live stream running after I disconnect from SSH?
Run FFmpeg as an enabled system service rather than as a foreground process in your SSH session. systemd can start it at boot and keep supervising it after the session closes, but you still need to check the service logs and YouTube Studio because process supervision does not prove that the broadcast is healthy.
How do I restart FFmpeg automatically if it crashes?
Add Restart=on-failure and a delay such as RestartSec=10, then reload systemd and restart the unit after saving the change. This can recover from some process failures, but it cannot correct a bad key, missing media, unsuitable encoding settings or a failed network path. Repeated failures may also meet systemd’s start-rate limits.
How much VPS bandwidth do I need for a YouTube livestream?
Start with the video and audio bitrate selected from YouTube’s current encoder guidance, then allow additional capacity for protocol overhead, reconnects and other activity. Measure sustained outbound performance on the actual VPS and check the provider’s current transfer terms. There is no universal Indian VPS size that proves a stream will remain healthy.