Skip to content
streamneo.
Troubleshooting13 min read

How to Fix Nginx RTMP Publishing Error: 403 Forbidden

Trace an NGINX RTMP publish rejection through the client URL, access rules, callback decision, and running configuration before changing settings.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

A 403 Forbidden message during an NGINX RTMP publish attempt means that the publishing connection has been rejected somewhere in the authorization path. There is no single fix that applies to every server: compare the client’s server, application and stream fields with the active configuration, then follow the publish rules and any authorization callback.

Start with one failed attempt and gather its exact client message, the relevant NGINX configuration and logs, and—if configured—the callback’s response. Until those pieces line up, changing a rule or weakening access controls is guesswork.

What a 403 publishing error means

Treat the error as a report of a rejected publish attempt, not as a diagnosis. The available evidence does not establish one universal cause or a universal NGINX log message for this condition. A client may display “403 Forbidden” while the server-side reason depends on its application settings, access rules, callback, module build or surrounding configuration.

First confirm that the message belongs to the RTMP publish attempt you are investigating. An HTTP 403 from a website, dashboard or reverse proxy is not necessarily an RTMP publishing rejection. Note the time of one attempt, the client’s full output, and which server log records activity at that time. If a callback is configured, note its corresponding request and response too.

The practical question is which layer rejected the connection. The URL may send the encoder to an unexpected application; a publish rule may reject the source address; an HTTP callback may decline authorization; or you may be inspecting a different NGINX installation or configuration from the one actually running. Each possibility calls for different evidence and a different smallest corrective change.

Do not solve uncertainty by allowing every publishing client or disabling authorization indefinitely. A temporary, controlled diagnostic can be useful in some environments, but it should not become the permanent configuration. Preserve the current config before edits, make one targeted change at a time, and retest with the same publisher and stream details.

Match server, app, and stream fields

Compare the URL entered in the publisher with the configuration for the RTMP service that receives it. The project documentation describes an RTMP URL in the form rtmp://rtmp.example.com/app[/name]: the server name identifies the destination, app is the application path, and the optional trailing component is the stream name. The application component should correspond to an application {} block in the effective RTMP configuration. See the nginx-rtmp-module project documentation for its URL and configuration context; confirm details against the fork and version actually installed.

Write down the publisher’s actual server or host, port, application, stream name, and any URL arguments. Compare them with the intended service and application block. Check spelling, letter case where relevant to your setup, trailing slashes, copied whitespace, and whether the client has an old stream profile saved. A correct stream name does not compensate for sending it to the wrong application, and a familiar hostname does not prove that the encoder reached the expected NGINX process.

The fields may appear in separate controls in your encoder. For example, one screen may ask for a server URL and a separate stream key or name. Assemble those values into the destination the client actually uses, rather than comparing only the label shown in the interface. If your service expects URL arguments for a token or other identifier, verify that the client sends them in the form the local configuration or callback expects; do not assume NGINX checks a stream key on its own.

A useful comparison is:

What to check Evidence to collect If it differs
Server and port Publisher destination and the address listening for RTMP Correct the client destination or investigate the intended listener; do not alter authorization rules to compensate for a wrong host.
Application path URL’s app component and the active application {} block Make the publisher path and intended block agree, or correct the configuration if the wrong block is serving the channel.
Stream name and arguments Client’s complete publish fields and callback’s expected identifiers Correct only the mismatched field, preserving any credential or token validation that the deployment requires.
Source address Address NGINX sees for the publishing connection and effective publish rules Confirm the intended address and rule before changing access policy.

This is also where a deployment mismatch can masquerade as a naming error. A host may resolve to a different machine, a container may expose another port, or multiple NGINX installations may use separate configuration trees. Check the destination actually reached in the server’s logs or other available connection evidence before concluding that a path typo is the cause.

Review publish access rules in order

Search the active RTMP configuration for allow publish and deny publish, including rules inherited from enclosing configuration blocks and rules local to the relevant application. The directives reference says access rules are checked in order of appearance. A later allow should not be assumed to override an earlier deny; read the effective sequence in context and determine which rule applies first to this client.

Check the action as well as the source. allow play and deny play govern playback, while publishing access uses the publish action. Changing playback controls will not correct a publishing rejection unless your investigation shows that you were diagnosing the wrong operation. The directives reference describes these rules, but it is a community wiki mirror, so verify its details against your installed module’s version and configuration.

Then verify the source address NGINX actually sees. The encoder’s public address, a private address on the local network, and the source address recorded by a server behind a proxy or network translation may differ. Do not pick an address based on what you expect the client to use; use connection or server evidence. Compare that observed address with the intended rule, and account for inherited rules before editing.

The project documentation includes an example that allows publishing from 127.0.0.1 and denies other publishers. That is a local-only example, not a general remote-encoder recipe. Copying it to a server intended to accept a remote publisher can reject that publisher precisely because NGINX sees a different source address. Similarly, making allow publish all permanent removes a meaningful boundary rather than identifying the cause. If a brief controlled diagnostic requires relaxing a rule, restrict the test to the necessary window and restore the intended policy immediately.

For a corrective change, adjust only the rule shown by the evidence to be mismatched: for example, correct an unintended source address or remove an earlier rule that conflicts with the documented policy. Keep a record of the prior sequence and retest the intended publisher. If the sequence or inheritance is unclear, inspect the complete active configuration before making an access decision.

Inspect on_publish authorization

If the application has an on_publish directive, trace that decision separately from the static access rules. The callback can send an HTTP request to an authorization service, and the module’s example explains that the HTTP return code is used to decide whether publishing is allowed. The project callback documentation is a starting point, but the callback’s actual request fields and expected responses depend on the deployed configuration and implementation.

Confirm whether the directive is present in the application serving this stream, and identify the exact endpoint it names. Establish that the running NGINX process can reach that endpoint, using the appropriate network and service logs rather than assuming that a successful request from your own computer proves reachability from NGINX. Check whether the callback received the request for the failed attempt and whether it logged a validation decision.

If the local implementation validates a shared secret, token or stream identity, compare the values actually received with the values it expects. Check URL arguments and any fields passed in the callback request, but do not invent a credential requirement: an RTMP password or stream key is not necessarily checked by NGINX itself unless the deployed configuration or callback implements that check. Preserve secrets when collecting logs for support and avoid publishing them in a test URL or article.

A callback decision may fail because the service is unavailable, because the request does not contain expected identifying fields, or because validation explicitly declines the publish attempt. Those are distinct findings. A reachable endpoint can still reject a request; a missing request points to a different place in the chain than a response that the callback intentionally uses to deny publishing. Capture the callback’s response as observed by NGINX and compare it with the endpoint’s own log for the same attempt.

The smallest valid change depends on that evidence. If the callback receives the wrong stream identity, correct the client fields or the callback’s mapping. If it cannot be reached, investigate the endpoint and network path. If it deliberately denies the request, review the intended authorization policy and the submitted credentials. Do not remove the callback simply to make a test publish succeed unless disabling it is an explicitly approved, bounded diagnostic and the access consequences are understood.

Check server logs and callback response

Correlate a single attempt across the publisher, NGINX RTMP logs and callback service logs, if one exists. Record the time and stream identity so that you are not comparing unrelated activity on a busy channel. Look for whether the request reached the expected server and application, whether a rule or callback appears to decide the outcome, and whether the callback’s recorded response matches what NGINX received.

The exact log text varies with the implementation and configuration; the evidence reviewed does not establish one message that appears for every 403. Do not treat the absence of a familiar phrase as proof that a rule is irrelevant. If existing logs do not capture enough detail, determine what additional logging is appropriate for your installed version and operational policy before enabling it. Keep credentials and tokens out of shared diagnostic excerpts.

Also establish which NGINX binary, service and RTMP module are running. A host can have more than one installation, and a container may run a separate configuration from the host service. Inspect the configuration belonging to the running process rather than editing a file merely because its path looks familiar. Confirm which RTMP implementation is installed and use instructions that match it.

The official NGINX Plus RTMP module instructions describe a packaged dynamic module for NGINX Plus. They are not a universal installation recipe for NGINX Open Source. The official NGINX Open Source installation documentation discusses third-party module installation, including compilation or dynamic loading; match the relevant steps to your distribution and build. The project’s documentation also describes a community module, which should not be assumed to behave identically to every package or fork.

When configuration changes are warranted, validate them with the method appropriate to the running binary and module, then reload according to your service’s normal process. The NGINX Plus page documents nginx -t and reload in its own module context; verify paths, privileges and commands for your installation rather than pasting commands from a different package. A successful syntax check confirms that a configuration parses, not that a callback will authorize the publisher or that the desired access policy is correct.

Test with the intended publisher

After collecting the baseline evidence and making a targeted change, test from the publisher the channel is meant to use. Keep the server, port, application, stream name and any expected arguments consistent with the real workflow. A command-line test from the server itself can help isolate a local-only rule, but success from 127.0.0.1 does not show that a remote encoder has the same source address or authorization path.

Change one thing at a time. If you alter the URL and the access list together, a successful attempt will not tell you which change mattered. Retest once, then correlate the client message with fresh server and callback logs. If the result changes, preserve the new evidence and update the configuration notes; if it does not, revert a speculative change before moving to the next hypothesis.

Use the findings to choose the next check:

Finding from the attempt Next step
No matching activity on the expected RTMP server Verify the host, port, listener, routing and active NGINX instance before editing publish authorization.
Request reaches an unexpected application Compare the URL app component with the intended application {} block and correct the mismatched destination or configuration.
Effective publish rule rejects the observed source Review rule order and inheritance, then make the smallest policy change that admits the intended publisher.
Callback receives the request and denies it Check the callback’s validation inputs and intended decision; do not bypass it without understanding the access consequences.
Callback does not receive the request, or NGINX cannot reach it Investigate whether the directive applies and whether the endpoint is reachable from the running service.
Evidence points to another binary, config or module Identify the running implementation and repeat checks against its active configuration and compatible documentation.

Once the intended publisher connects, do not stop at a test performed under relaxed rules. Restore the production access policy, then make a fresh publish attempt using that policy. Confirm that a legitimate publisher succeeds and that any restrictions you rely on remain in place. This verifies the configuration you intend to operate, rather than a temporary diagnostic state.

If the attempt still fails and the evidence does not identify the rejecting layer, keep the configuration unchanged and ask the administrator of the RTMP service to review the exact client output, effective application config, ordered publish rules, server logs and callback request/response. A useful report says what was tested and what the logs showed; it does not assert a cause based on the error label alone. For a broader comparison of keeping a publishing workflow on your own machine or moving it elsewhere, see how a cloud service differs from OBS for a continuous stream. If your NGINX deployment itself runs on a cloud virtual machine, the Google Compute Engine playlist livestream guide is relevant to that hosting context, not a remedy for authorization.

For ongoing channels, distinguish a rejected publish from a stream that connected and later dropped. The latter needs a different investigation; the guide to dropped frames in a browser-based cloud encoder covers a separate failure mode. If the recurring task is a prerecorded YouTube loop rather than operating your own RTMP server, the electricity-use guide for prerecorded 24/7 streams may help you assess the operating arrangement. Neither topic replaces checking the authorization path for this error.

If your specific difficulty is keeping a continuous YouTube broadcast running after your computer is switched off, StreamNeo removes that particular always-on-computer burden by turning an uploaded video into a YouTube live stream; it does not diagnose or repair an NGINX RTMP authorization rejection.

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 every NGINX RTMP 403 mean the stream key is wrong?

No. The available evidence does not establish that mapping, and a key is only checked if the deployed configuration or its authorization callback implements that check. Compare the URL fields, publish rules and callback behavior before changing credentials.

Should I add allow publish all to test?

Not as a lasting fix. It can remove the restriction that protects publishing access, while still leaving a URL mismatch or callback rejection unresolved. If an administrator uses a brief controlled diagnostic, they should restore the intended restrictions immediately and test again under the production policy.

Can I follow NGINX Plus module instructions on any NGINX server?

No. The official NGINX Plus page describes its packaged dynamic module, while NGINX Open Source may use a third-party module built or loaded for that installation. Identify the running binary and module first, then follow compatible documentation.

What evidence should I send an administrator?

Send the exact publisher destination with secrets redacted, the intended application and stream name, the active relevant configuration, and logs for one timed attempt. Include the callback request and response if one is configured, and identify which NGINX service and module were checked.

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 ↗