# nginx-live-win32: a Windows nginx build with RTMP, HTTP-FLV and a GOP cache

> This repository ships a prebuilt Windows package of nginx plus the nginx-live-module, with Enhanced RTMP for HEVC, AV1, VP9 and Opus, an HTTP-FLV endpoint, a JSON status interface, and a service wrapper for the system tray. The stream table is per worker, so production is told to keep worker_processes at 1.

**illuspas/nginx-live-win32** — nginx-live-module Windows builds. 

- Repository: https://github.com/illuspas/nginx-live-win32
- Stars: 1,058 · Forks: 419
- Language: HTML
- License: not declared
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/illuspas-nginx-live-win32

## A green package, not a build guide

This repository is not the source of nginx or of the module. It is the Windows green package of nginx plus nginx-live-module, meaning a self-contained archive that runs after extraction with no installation step. The module itself lives in a separate repository, illuspas/nginx-live-module.

The stated purpose is a high performance, low latency open source live streaming server, supporting RTMP, Enhanced RTMP and HTTP-FLV for both publishing and playback.

A second executable is bundled, nginx_service.exe, which registers nginx as a Windows service and provides a system tray management interface. The point of that is to remove the two things that make running nginx on Windows awkward in practice, the absence of an init system and the absence of a service model.

The distribution channel is a release page, where the archive is named nginx-live-<version>-win32.zip, with a SHA256SUMS.txt checksum file alongside it and the build provenance for each version in the release notes. The repository also contains the same runnable package, so cloning it works as an alternative to downloading. The repository top level confirms the shape: nginx.exe, nginx_service.exe, a conf directory, an html directory for static files, a logs directory, a temp directory, a LICENSES directory, THIRD-PARTY-NOTICES.md and BUILD-INFO.txt.

That last file deserves attention. The documentation says the version number, compile flags, executable size and SHA256 are generated into BUILD-INFO.txt by the build script, and that this file is the authority: do not edit it by hand and do not write the version in the README by hand. The release entries follow the same discipline, naming the combination explicitly, for example nginx-live v2.0.2 with nginx 1.31.6 and nginx-live-module 2.0.2, and the earlier v2.0.1 pairing nginx 1.31.6 with module 2.0.0.

## What the module adds to plain nginx

Plain nginx serves static files and proxies HTTP. The live module adds the streaming layer, and the feature list is where the engineering decisions are visible.

On the ingest side, RTMP publishing and playback work with tools like OBS and FFmpeg, and Enhanced RTMP v1 gives native support for HEVC, AV1, VP9 and Opus, forwarded directly without transcoding. That is the feature that matters most for anyone with a modern encoder, since a transcode is both a CPU cost and a quality loss. HTTP-FLV publishing over POST and playback over GET work as well, with HTTP/1.1 chunked, and there is WS and WSS-flv for publishing and playback.

The playback side has a GOP cache, so a viewer can join from the most recent keyframe, within one GOP. Without it, a client connecting mid-stream waits for the next keyframe, which on a long GOP can be tens of seconds. The configuration exposes it as gop_cache on, with a default of on.

Access control is by allow and deny directives for publish and play, with CIDR support, and the same rules are shared between RTMP and HTTP-FLV. The order of the directives matters and is documented as matched in the order written.

The JSON status interface at /stat returns the stream list, whether a stream is being pushed, the client count, the audio and video codecs, byte counters and the running time, which is enough to build a monitoring view without parsing logs.

There is also slow consumer protection, which is the feature that separates a server meant for real viewers from a demo. When the pending queue for a subscriber exceeds a limit, frames are dropped and the stream resynchronises; a subscriber that stays stuck is disconnected on its own without affecting the others.

## The configuration, and the two lines that matter most

The configuration file conf/nginx.conf is shipped as an example, and it is short enough to read as a template.

```nginx
rtmp {
    server {
        listen 1935;              # RTMP 监听
        gop_cache  on;            # GOP 缓存（秒开）
        chunk_size 65535;

        application live {
            live             on;  # 推拉开关
            # allow publish 127.0.0.1;   # 可选：访问控制
            # deny  publish all;
        }
    }
}

http {
    server {
        listen 8080;

        location ~ ^/[a-z0-9_]+/.+(\.flv)?$ {
            live_flv  on;         # HTTP-FLV 推/拉流端点 /<app>/<stream>[.flv]
        }

        location = /stat {
            live_stat  on;        # JSON 状态接口
        }
    }
}
```

The default ports are 1935 for RTMP, with the application named live, and 8080 for HTTP, carrying HTTP-FLV and the status page.

The directive table gives the defaults: live defaults to off, so publishing and playback return 503 while it is off, and the live_flv and live_stat directives also default to off and are enabled per HTTP location. The timeout directive defaults to 60 seconds and covers the handshake, send stalls and publish idle. The chunk_size default of 65535 is the RTMP outbound chunk size.

Two lines deserve particular attention before you run this anywhere. The first is that the stream table is per worker, and the documentation recommends keeping worker_processes at 1 in production. That is a genuine architectural constraint rather than a tuning hint: with several workers, a stream published to one worker is not visible to a client connected to another, so playback fails intermittently.

The second is the reload behaviour. After a reload, a new worker's stream table is empty and existing streams are invisible to new connections. For long-lived connections the documentation suggests configuring worker_shutdown_timeout.

## Codec support, and the limits of Enhanced RTMP

The codec support splits cleanly by container.

| Type | legacy FLV | Enhanced RTMP v1 (FourCC) |
|------|-----------|---------------------------|
| Video | H.264 | HEVC hvc1, AV1 av01, VP9 vp09 |
| Audio | AAC, MP3 and similar | Opus, ac-3, ec-3,.mp3, fLaC |

So an H.264 stream in a legacy FLV container carries H.264 video with AAC audio, which is what every legacy tool expects. The newer codecs need the Enhanced RTMP container with FourCC signalling, which is why the publish commands in the documentation use the same FLV output but the source codec determines whether the legacy or enhanced path is taken.

The publish examples show that in practice:

```bash
# H.264 + AAC
ffmpeg -re -i input.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/mystream

# HEVC/AV1/VP9/Opus 源直接 copy（Enhanced RTMP 封装，无需转码）
ffmpeg -re -i input_265.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/hevc
```

And HTTP-FLV publishing over POST works with the same copy approach:

```bash
ffmpeg -re -i input.mp4 -c copy -f flv http://127.0.0.1:8080/live/mystream
```

The known limitations are worth reading because they bound the compatibility envelope. The old Flash-era RTMP H.265 extension with the cdn_cn flv_265 standard is not supported, and AMF3 commands with objectEncoding=3 are not supported. So a client that speaks the older Chinese CDN H.265 convention, or a publisher using AMF3 object encoding, will not work against this server.

The client compatibility table is a separate axis from the codec table, and it is more restrictive. OBS 29.1 and later supports H.264, HEVC and AV1 but not VP9. FFmpeg and FFplay 6.1 and later support all four. NodePlayer.js 1.0 and NodeMediaClient 3.0 support H.264 and HEVC but not VP9 or AV1.

## Running it, and what the package does not grant you

The operating instructions are four commands. Double-click nginx.exe to run it directly, run nginx_service.exe for the service and tray management route with install, start, stop, uninstall and open config options, use nginx.exe -s stop to stop from the command line, and nginx.exe -s reload to reload the configuration.

Publishing with OBS means setting a custom server at rtmp://<server IP>:1935/live with an arbitrary stream key, which is the stream name. Playback works with ffplay over RTMP at rtmp://127.0.0.1:1935/live/mystream, or over HTTP-FLV at http://127.0.0.1:8080/live/mystream.flv. The status page is read with curl -s http://127.0.0.1:8080/stat.

What the package does not grant you is a public server. There is no TLS configuration guidance in the shipped config, no reverse proxy example, and no discussion of the firewall or NAT rules needed to expose 1935 or 8080. For a server intended to face the internet, the operator has to bring that.

The licensing is handled carefully, which is the right thing for a repackaged distribution. The licence texts of all components are bundled in the LICENSES directory, with the full list and copyright statements in THIRD-PARTY-NOTICES.md. nginx is under BSD 2-Clause, the nginx-live-module and the service manager under Apache License 2.0, OpenSSL under Apache License 2.0, PCRE2 under BSD 3-Clause with the PCRE2 exception, and zlib under the zlib licence. The documentation also states that nginx is a registered trademark of Nginx, Inc, that this package is an independent third-party build, and that it has no affiliation with Nginx, Inc.

On maintenance, the repository is not archived, the last push was on 2026-10-12, and the recent releases are v2.0.2 on 2026-10-11 and v2.0.1 on 2026-10-05. The older v1.2.1 from 2018-04-18 shows how long the line has been running, and the version jump from 1.x to 2.x marks the move to the current module generation.

## Conclusion

nginx-live-win32 fits someone who needs a live streaming server on Windows without setting up a Linux box, and who wants Enhanced RTMP so that HEVC, AV1, VP9 and Opus sources can be forwarded without transcoding. It is a poor fit if you need the old Flash-era RTMP H.265 extensions or AMF3 commands, and a poor fit for a multi-worker deployment, because the stream table is per worker. Before adopting, read BUILD-INFO.txt for the exact nginx and module versions and compile flags in the package you downloaded, keep worker_processes 1 as the documentation recommends, and verify the SHA256SUMS.txt checksum for the release you pull.

## FAQ

### What is nginx-live-win32 and what does the package contain?

It is a Windows green package combining nginx, the nginx-live-module and a service manager, runnable after extraction with no installation. It provides RTMP, Enhanced RTMP and HTTP-FLV for publishing and playback, and the package includes nginx.exe, nginx_service.exe for service and tray management, a conf directory, an html directory, a logs directory and a temp directory.

### How do I publish a stream to nginx-live-win32 with ffmpeg?

For H.264 with AAC, run ffmpeg -re -i input.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/mystream. For HEVC, AV1, VP9 or Opus sources, the same copy command produces the Enhanced RTMP container without transcoding, and HTTP-FLV publishing over POST is done with the same command pointed at http://127.0.0.1:8080/live/mystream.

### Why does the documentation recommend worker_processes 1?

Because the stream table is per worker, so with several workers a stream published to one worker is not visible to a client connected to another, and playback fails intermittently. There is a related limitation where after a reload a new worker's stream table is empty and existing streams are not visible to new connections, with worker_shutdown_timeout suggested for long-lived connections.

### Which codecs does nginx-live-win32 support?

Legacy FLV carries H.264 video with AAC and similar audio. Enhanced RTMP v1 with FourCC signalling adds HEVC as hvc1, AV1 as av01, VP9 as vp09, and Opus, ac-3, ec-3, .mp3 and fLaC for audio. The old Flash-era RTMP H.265 extension and AMF3 commands are not supported.

### How do I check the running streams and their statistics?

Request the JSON status interface at /stat, for example with curl -s http://127.0.0.1:8080/stat. It returns the application and stream list, whether a stream is being pushed, the client count, the audio and video codecs, byte counters and the running time. The endpoint is enabled with the live_stat on directive in the HTTP location.

## Sources

- [illuspas/nginx-live-win32 on GitHub](https://github.com/illuspas/nginx-live-win32)
- [Issues](https://github.com/illuspas/nginx-live-win32/issues)
- [README](https://github.com/illuspas/nginx-live-win32/blob/master/README.md)
- [Releases](https://github.com/illuspas/nginx-live-win32/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/illuspas-nginx-live-win32
