If you run FFmpeg on a Linux machine, systemd can keep the encoder running after you close SSH, relaunch it after certain failures, and start it again when the machine boots. It supervises the local process; it cannot guarantee uninterrupted playback or repair a missing file, broken network, invalid YouTube event, or rights problem.
The practical pattern is to run FFmpeg in the foreground under a dedicated, unprivileged account, keep credentials out of the unit file, and check both the local service and YouTube Live Control Room. The examples below are templates: adapt paths, account names, media settings, and the current RTMPS details for your host and stream.
What systemd can and cannot keep running
A systemd service gives Linux a defined process to manage. If you start FFmpeg from an SSH shell, that process is tied to a session unless you take additional steps to detach it. A service instead runs under systemd, so closing the terminal does not itself stop the broadcast. You can also enable the service to start at boot and choose whether systemd should try again after an eligible failure.
That is process supervision, not end-to-end stream monitoring. A service may be active while FFmpeg is unable to read its input or YouTube is not receiving usable media. A successful local start does not establish that the live event is still open, that the stream key is valid, that the network route allows the connection, or that YouTube accepts the media settings.
Keep the failure boundary clear:
| What fails | What systemd may do | What still needs attention |
|---|---|---|
| FFmpeg exits with a qualifying failure | Restart it according to the unit policy | Read the journal to find the cause and check whether a retry is sensible |
| The host reboots | Start an enabled service during boot | Confirm network readiness and that the live event can accept the restarted feed |
| The input file is missing or unreadable | Restart FFmpeg if it exits and the policy applies | Correct the path or permissions; repeated retries do not restore the file |
| The network, key, or YouTube event is unusable | Restart attempts may happen, but may fail again | Check connectivity, current credentials, event state, and Live Control Room health |
| Content is interrupted for a rights issue | Nothing useful can be fixed by relaunching FFmpeg | Resolve rights and platform status with the appropriate parties |
The distinction matters overnight: an active service is evidence about a local process, not a promise that viewers can hear a continuous programme. If continuity of a pre-recorded programme matters, decide whether restarting a loop from its beginning is acceptable. For a playlist workflow, see how a video playlist can be used for an always-on stream; the source logic and the service supervisor solve different problems.
Run FFmpeg as a foreground service process
Systemd needs to supervise the actual long-running process. Run FFmpeg directly as the service's main process rather than starting it in the background with &, wrapping it in a shell that exits, or using a detached-session tool. If the process systemd tracks exits, systemd can apply the unit's restart policy. If a wrapper stays alive while a child encoder has died, the unit can appear active without doing the job you intended.
A unit template might look like this:
[Unit]
Description=Indian music YouTube live stream
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=ytstream
Group=ytstream
WorkingDirectory=/srv/ytstream
EnvironmentFile=/etc/ytstream/stream.env
ExecStart=/usr/bin/ffmpeg -re -stream_loop -1 -i /srv/ytstream/programme.mp4 -c:v copy -c:a copy -f flv "${YOUTUBE_RTMPS_URL}/${YOUTUBE_STREAM_KEY}"
Restart=on-failure
RestartSec=15
[Install]
WantedBy=multi-user.target
Treat this as a shape, not a tested recipe. In particular, -stream_loop -1 is appropriate only for an input and use case where looping is intended; copying codecs works only if the source streams and the target ingest workflow support them. Your FFmpeg build, file, audio/video codecs, YouTube's current ingest instructions, and endpoint format determine the real command. Do not copy a bitrate, codec, or GOP value from an unrelated example as if it were universal.
The command must remain in the foreground. Do not add daemonising flags or a shell background operator. Use the installed FFmpeg path, confirm that the service account can execute it, and quote values carefully if you build the command from environment variables. Some encoder interfaces accept an RTMPS address and stream name separately, while others expect the endpoint and key to be joined. Check how your exact FFmpeg command handles the URL rather than assuming every tool uses the same format.
For the current endpoint and key, use YouTube Live Control Room. YouTube's RTMPS guidance directs creators to use RTMPS rather than plain RTMP and includes troubleshooting guidance for connection setup. The Live Streams API documentation describes ingestion address fields for API-based workflows. Those documents help with endpoint format; they do not validate your particular event or command.
Create a dedicated unprivileged service account
Avoid running a continuous encoder as root. Create a separate system account for the stream, such as ytstream in the template, and assign only the access the process needs. The exact account-creation command depends on the Linux distribution and local policy, so use the distribution's documented method rather than pasting an unreviewed command from a different host.
The account needs permission to read the media file, traverse its parent directories, read any non-secret configuration it uses, and execute FFmpeg. It normally does not need permission to edit the programme, change system services, or administer the machine. A narrow read-only arrangement reduces the consequences of a mistake in the encoder command, but it does not eliminate the need to keep the host and its credentials secure.
Check the whole path, not just the file's owner. A file can be readable while a parent directory prevents access. Test access as the service account, and inspect the service journal after the first start for permission errors. If you store several programmes in a directory, grant access to only the required directory or files where practical. Avoid broad permissions as a quick fix, especially on a machine that holds other accounts' data.
The same principle applies to logs and temporary files. Decide where FFmpeg writes any output, ensure the service account can use that location, and avoid putting the stream key in a command line that may be exposed through process listings or copied into a support request. Review exactly what your unit and command reveal before sharing them.
Configure network ordering and working directory
A live encoder needs a network route to YouTube, but After=network-online.target is an ordering relationship, not a network repair mechanism. The template pairs it with Wants=network-online.target, which asks systemd to bring in that target where the relevant network manager provides it. Whether the target waits for a usable connection depends on the host's network configuration and its wait-online service. Consult the systemd and distribution documentation for the machine you administer.
If a local machine uses Wi-Fi that takes time to associate, or a VPS applies network configuration during boot, ordering can reduce the chance that FFmpeg starts before the expected network setup. It cannot ensure that DNS works, a route is reachable, the firewall permits the connection, or the path remains healthy later. If startup races are suspected, compare the service start time and journal messages with the network manager's own logs rather than repeatedly changing restart values.
WorkingDirectory sets the process's initial current directory. An absolute path in ExecStart is generally easier to audit than relying on relative paths, but a working directory can still make related files or scripts predictable. Use a directory the service account can traverse, and avoid placing secrets in a directory with broad read access. Make sure the host has adequate upload capacity and a sufficiently reliable network for the actual stream; systemd does not create either one.
For readers choosing between a machine already on site and a rented host, the decision is about administration and connection as much as software. An existing Linux machine avoids a new hosting arrangement but must stay powered and connected; a rented Linux VPS can be useful when you do not have an always-on machine, but you must understand its network, access, and ongoing cost. Compare available upload capacity, recovery access when you are away, your comfort administering Linux, and whether the selected host can run your intended FFmpeg workflow. The Indian cloud VPS loop guide covers the host question; this article addresses what systemd does once a Linux host is available.
Protect stream credentials in an environment file
Keep the real stream key out of the unit text, screenshots, shell history, and shared troubleshooting messages. A systemd environment file is one way to keep configuration separate from the unit, but it is still a secret-bearing file. Store it somewhere with restrictive ownership and permissions, and make sure only the administrator and the service mechanism that needs it can read it.
For example, /etc/ytstream/stream.env could contain placeholder names like these:
YOUTUBE_RTMPS_URL=rtmps://current-address-from-live-control-room
YOUTUBE_STREAM_KEY=replace-with-private-key
These are placeholders, not a working endpoint or key. Get the current RTMPS address and stream key from the live event's settings. Never publish the real values in a blog, ticket, terminal capture, or support request. If you believe a key has been exposed, use YouTube's current controls to replace or reset it, then update the protected configuration and restart the service deliberately.
Environment-file syntax and how a particular command expands variables are easy places to make a subtle mistake. Systemd reads the file for the service environment; it does not make arbitrary shell substitutions in every ExecStart form. Verify the syntax against the systemd version and test with a placeholder or a non-live setup before relying on it. Avoid putting secrets into a shell command merely to work around quoting. Also check the FFmpeg error output: applications can include connection details in diagnostics, so treat logs as potentially sensitive until you know what they contain.
A valid key is necessary but not sufficient. The event must still be available to receive the feed, and the endpoint and key must correspond to the intended live event. Re-check them when a stream is recreated or the event changes. Do not leave a stale key in an old unit or a copied configuration file that someone else can access.
Set restart behaviour and inspect service logs
Restart=on-failure is a deliberate baseline for an encoder that should return after an unexpected failure. According to the systemd service documentation, this policy covers cases such as a non-zero exit, certain signals, qualifying operation timeouts, or watchdog timeouts. It does not mean “restart whenever anything is wrong”: a service systemd intentionally stops is not restarted under this setting.
A delay such as the template's RestartSec=15 is only an example. Choose a pause that avoids an immediate retry loop and suits the host's connection behaviour. Too short a delay can generate repeated connection attempts while a known problem persists; a longer delay means a failed process remains down for longer before the next attempt. Neither choice repairs a bad key, a missing input, or a closed event.
Systemd also applies start-rate limiting. If a service repeatedly fails, it can eventually be left in a failed state rather than retried indefinitely. When retries stop, check the unit's restart policy, start-limit settings, and journal before changing limits. Increasing the allowance without finding the underlying fault can simply produce more attempts against the same failure.
After saving a unit, reload systemd's unit definitions, start the service, and inspect both its status and recent journal entries. Use the unit name you chose in place of ytstream.service:
sudo systemctl daemon-reload
sudo systemctl start ytstream.service
sudo systemctl status ytstream.service
sudo journalctl -u ytstream.service -n 100 --no-pager
The commands above are administrative examples; paths and privilege policy vary by host. Look for whether FFmpeg launched, whether it could open the input, whether it reached the expected endpoint, and whether it reported an error before exiting. Status and logs answer local questions. If the log includes private connection details, redact them before sharing. Once the unit behaves as intended, enable it for boot with systemctl enable ytstream.service; enabling is distinct from starting it now.
A journal line saying the process is active is not proof of incoming media. If FFmpeg is alive but output is silent or YouTube reports a problem, investigate the source and output path rather than treating a green service state as confirmation. For an audio-focused channel, this guide to consistent podcast audio levels addresses a different part of the chain: the sound reaching viewers, not process recovery.
Test reboot and failure recovery alongside YouTube checks
Do a controlled test before depending on the service overnight. First confirm the correct file plays and that the intended event is available. Start the service, check the journal for input and connection errors, and then use YouTube Live Control Room's preview or stream-health information to confirm that YouTube is receiving usable media. YouTube's stream health guidance can help interpret its status. A running local process and a healthy incoming stream are separate checks.
Then test the recovery cases you actually depend on. Close the SSH session and confirm that the unit remains active. For reboot behaviour, enable the unit and schedule a reboot when you can monitor both the host and the YouTube event. Confirm that the service starts and that the incoming stream recovers; do not assume a boot-time process launch means YouTube resumed the same event successfully. Decide in advance whether the stream can restart the file from its beginning without confusing viewers.
You can test process-failure handling in a controlled maintenance window, but be precise about the test. Stopping a service intentionally is not the same as making FFmpeg fail, and Restart=on-failure is not supposed to undo every deliberate stop. Use a harmless test input or a planned non-public event where possible. After observing a restart, inspect the journal and verify the YouTube side again. Avoid testing by exposing the live key or disrupting a public stream without a plan.
If connection fails, check the current RTMPS URL and key, the correct endpoint and path, the host's DNS and network route, and whether any firewall permits the required connection. YouTube's RTMPS help discusses port 443 where it is needed for the connection. A local restart cannot make a blocked route pass or turn a plain RTMP address into the current RTMPS ingest address. If the process is running but the Live Control Room does not show usable media, compare its diagnostics with FFmpeg's output and correct the fault at its source.
Do not treat music rights as a separate issue that automation can solve. YouTube's Live Stream Terms state that the streamer represents and warrants having the necessary rights for live content, including music licensing rights. YouTube says live streams are scanned for third-party content; identification can lead to a placeholder and warning, and continued use can lead to interruption or termination. Even licensed music can still be interrupted unless the rights owner has added the channel to its Content ID allowlist. YouTube also says Creator Music does not support licensing for live content, so selecting a track there does not clear a livestream.
A playlist, a purchase of a recording, attribution, or a “no copyright intended” note does not by itself establish the rights needed to stream a song. Rights can differ by recording, composition, territory, and intended use. Confirm the relevant permissions with rights holders or a qualified rights adviser before launch, and check YouTube's current official guidance. For a broader look at the issue, see whether podcast episodes can be livestreamed without copyright problems. A service restart cannot restore a stream interrupted because its content or event is not permitted.
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 keep an FFmpeg YouTube stream running after SSH disconnects?
Run FFmpeg as the foreground process of a systemd service rather than starting it from an interactive SSH shell. Systemd owns the service process, so ending the SSH session does not by itself stop it. Check service status and YouTube's incoming stream health separately.
Will systemd restart FFmpeg after every failure?
No. With Restart=on-failure, systemd restarts after documented failure conditions, but not after every intentional stop. Repeated failures can also hit start-rate limits, so inspect the journal and fix the cause rather than assuming retries will continue forever.
Does a running service prove YouTube is receiving the stream?
No. FFmpeg can be alive while its input, connection, event, or output is unusable. Check the local journal and the Live Control Room's preview or stream-health information to verify both sides.
Can I use Indian songs in a YouTube live stream if FFmpeg loops them?
Looping a file has no bearing on whether you have the necessary streaming rights. Confirm rights for the specific song, recording, territories, and use, and consult YouTube's current rules; live content can be scanned and interrupted even when a streamer believes music is licensed.