{"id":22221430,"url":"https://github.com/better-call-jason/nginx-streaming-server-app","last_synced_at":"2025-11-08T06:03:08.701Z","repository":{"id":195220284,"uuid":"692490355","full_name":"Better-Call-Jason/nginx-streaming-server-app","owner":"Better-Call-Jason","description":"Easy To Use NGINX RTMP HLS All-In-One Receiver/Broadcaster Streaming Server with instructions on how to incorporate with OBS","archived":false,"fork":false,"pushed_at":"2023-09-17T18:27:19.000Z","size":1390,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-14T13:05:15.403Z","etag":null,"topics":["livestreaming","nginx","rtmp-server","rtmp-streaming","streaming","streaming-server","streaming-video","video-js"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Better-Call-Jason.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-09-16T16:32:17.000Z","updated_at":"2024-11-15T02:21:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"7bb38d5c-2c79-4611-9910-9088fafa08f9","html_url":"https://github.com/Better-Call-Jason/nginx-streaming-server-app","commit_stats":null,"previous_names":["better-call-jason/nginx-streaming-server-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Better-Call-Jason/nginx-streaming-server-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Better-Call-Jason%2Fnginx-streaming-server-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Better-Call-Jason%2Fnginx-streaming-server-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Better-Call-Jason%2Fnginx-streaming-server-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Better-Call-Jason%2Fnginx-streaming-server-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Better-Call-Jason","download_url":"https://codeload.github.com/Better-Call-Jason/nginx-streaming-server-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Better-Call-Jason%2Fnginx-streaming-server-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272800967,"owners_count":24995185,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["livestreaming","nginx","rtmp-server","rtmp-streaming","streaming","streaming-server","streaming-video","video-js"],"created_at":"2024-12-02T23:13:31.392Z","updated_at":"2025-11-08T06:03:08.623Z","avatar_url":"https://github.com/Better-Call-Jason.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Own Your Stream --- Toolkit For Online Freedom Episode 1\n\nFollow the steps below to set up your own streaming server. \n\n![alt text](https://github.com/Better-Call-Jason/nginx-streaming-server-app/blob/main/episode1-thumbnail2.png?raw=true)\n\n## Table of Contents\n\n1. [About](#about)\n2. [Getting Started](#Prerequisites)\n3. [Set Up](#setup)\n4. [Build Your Receiver](#receiver)\n5. [Build Your Broadcaster](#broadcaster)\n6. [Add SSL](#ssl)\n7. [Configure OBS](#obs)\n8. [Configure Analytics and Firewall](#tcpdump)\n9. [Build Your Viewer](#viewer)\n10. [Go Live](#final)\n11. [Keep Your Stream Secure](#secure)\n12. [Donate](#donate)\n13. [Parting Shot](#goodbye)\n\n## \u003ca name='about'\u003e\u003c/a\u003eAbout\n\nI have directly seen the power that big tech has over our lives. In a very small way, I'd like to push back against that trend towards an unaccountable inhumane centralized quasi-corporate-government machine and dissent against the power it wields over us. I don't want to continue seeing voices of dissent and critique marginalized and cancelled by big tech at the behest of governments and corporations simply for offering alternative opinion that is contrary to and critical of the experts and authorities. While that statement includes the last three and a half years for sure, it also includes marginalized and alternative opinions about many events and actions throughout history. The solution to the problem of big tech is to decentralize the internet. We should have independent spaces online that preserve privacy and allow genuine community among like minded individuals and polite dissenters. Here, I will show you how to create your own live streaming server which is one piece of that larger solution puzzle. While, I built this project on a very small cheap compute instance, this streaming server application is a fully scalable secure model that can be used on more powerful compute instances to broadcast your live stream (radio or video) content to thousands of followers similar to what Twitch, Youtube, Facebook, Rumble, Discord and others provide. This application will also work very well on a Raspberry PI 4B for those who want additional privacy, security and ownership. Follow these steps below to begin the process of becoming unstoppable by big tech.\n\nThanks, \nJason\n\n## \u003ca name='Prerequisites'\u003e\u003c/a\u003eGetting Started\n\n- download obs : https://obsproject.com\n- purchase domain : https://domains.squarespace.com\n- create cloud account  \n    - create linode account : https://www.linode.com  \n    - create aws account : https://aws.amazon.com\n- access your cloud account \u003cbr /\u003e\n    - linode account : https://cloud.linode.com/linodes\u003cbr /\u003e\n    - aws/lightsail : https://lightsail.aws.amazon.com/ls/webapp/home/instances\u003cbr /\u003e\n    - create your instance with  `ubuntu 20.04`\u003cbr /\u003e\n    - Hate cloud computers? This entire project can exist on a Rasberry PI 4B \u003cbr /\u003e\n- point your domain to your created instance's ip\n    - navigate to your domain dns\n    - create an A record\n    - enter a subdomain or leave blank or @\n    - address - enter instance ip address\n    - TTL - 60 seconds or minimum\n  \n## \u003ca name='setup'\u003e\u003c/a\u003eSet Up\n\nSSH into your instance and let's begin setting up your streaming server, we'll first update the instance and then install our server application called NGINX\n\n- update instance  \n    ```sudo apt update```  \u003cbr /\u003e\n    ```sudo apt upgrade``` \u003cbr /\u003e\u003cbr /\u003e\n- install nginx - server application  \n    ```sudo apt install nginx```\u003cbr /\u003e\u003cbr /\u003e\n- check status  \n    ```systemctl status nginx```  \n    `ctl` + `c` to exit the server\n    \nIf Nginx is running correctly, you will see a green Active status.\n\n## \u003ca name='receiver'\u003e\u003c/a\u003eBuild Your Receiver\n\nNow, let's set up your receiver so your server can receive your live stream signal. \n\n- install nginx rmtp module, our receiver module  \n    ```sudo apt install libnginx-mod-rtmp```\u003cbr /\u003e\u003cbr /\u003e\n- restart nginx   \n    ```sudo systemctl restart nginx```\u003cbr /\u003e\n    ```systemctl status nginx```  \u003cbr /\u003e\n    `ctl + c` to exit\n\n- configure nginx to receive stream  \n    ```sudo nano /etc/nginx/nginx.conf```  \n- copy and insert this code below at the bottom of the page\u003cbr /\u003e\n\n```\nrtmp {\n    server {\n        listen 1935;\n        chunk_size 4096;\n\n        application live {\n            live on;\n            record off;\n            # allow publish YOUR_LOCAL_IP_ADDRESS;\n            # deny publish all;\n\n            # Setup HLS\n            hls on;\n            hls_path /mnt/hls/;\n            hls_fragment 3;\n            hls_playlist_length 60;\n            #deny play all;\n            allow play all;\n        }\n    }\n}\n```\n- after pasting click `ctl` + `s` and then `ctl` + `x`\u003cbr /\u003e\n\n## \u003ca name='broadcaster'\u003e\u003c/a\u003eBuild Your Broadcaster\n\nNow, let's set up your broadcaster so your server can beam your live stream signal to surfers on your website. \n\n- configure nginx to broadcast the stream  \n    `sudo nano /etc/nginx/sites-available/default`\n\ndelete all existing code and paste the code below :\n```\nserver {\n\n      listen 80 default_server;\n    listen [::]:80 default_server;\n\n    root /var/www/html;\n    index index.html;\n\n    server_name your domain name;\n\n    location / {\n        try_files $uri $uri/ =404;\n    }\n\n    location ~ ^/live/?$ {\n        rewrite ^/live/?$ /stream.html break;\n    }\n\n    location /hls {\n        types {\n          application/vnd.apple.mpegurl m3u8;\n          video/mp2t ts;\n     }\n     alias /mnt/hls/;\n     expires -1;\n     add_header 'Cache-Control' 'no-cache';\n     }\n }\n```\n- after pasting click `ctl` + `s` and then `ctl` + `x`\u003cbr /\u003e\n\n## \u003ca name='ssl'\u003e\u003c/a\u003eAdd Security\n\nNow, let's set up the security of your server and application. These next steps require that you've purchased a domain and followed the steps to set up an A record. It can take a while for this to work. So if it fails, give it some time before trying again.\n\n- install certbot and let's encrypt  \n    `sudo apt-get install certbot python3-certbot-nginx`\n    \n- create the ssl for your domain  \n    `sudo certbot --nginx -d your domain name`\n    \n- automate the renewal of your domain ssl  \n    `sudo certbot renew --dry-run`\n    \n   - add a cron job to manage the renewal  \n    `sudo crontab -e`\n    \n   - enter this line at the bottom and save and exit  \n    `0 12 */10 * * /usr/bin/certbot renew --quiet`\n    \n   - see active scheduled cron jobs  \n    `sudo crontab -l`\n- recheck nginx after certbot completes  \n`sudo nano /etc/nginx/sites-available/default`\n\nshould see changes and 443 code added\n\n## \u003ca name='obs'\u003e\u003c/a\u003eConfigure OBS\n\nNow, let's set up your OBS software to broadcast to your receiver\n\n- Open OBS Studio on your PC or Mac.\n    \n- Click on `Settings` in the bottom right of the OBS Studio window.\n    \n- In the settings panel, click on `Stream`.\n    \n- Here, under `Service`, select `Custom...`.\n    \n- In the `Server` field, enter the RTMP URL of your Nginx server. The URL would be in the format: `rtmp://\u003cYour_Server_IP\u003e/live`.\n    \n- set your stream key, that will be needed later.  \n    `YOUR_STREAM_KEY`\n      - FYI you will need your stream key to be used in building the viewer\n    \n- Click on `Apply` and then `OK`.\n\n## \u003ca name='tcpdump'\u003e\u003c/a\u003eConfigure Analytics and Firewall\n\nTCP Dump allows us to do some checks on the live stream when it is broadcasting which will allow troubleshooting if the need arise\n\n- install tcpdump to see the operation of the livestream  \n    `sudo apt-get install tcpdump`  \n    `sudo tcpdump -i any port 1935`\n    `ctl` + `c` to exit the stream\n    \n- open firewall port 1935 on lightsail it is closed, this is done in networking on the instance\n    \n- open firewall port 433 on lightsail it is closed, this is done in networking on the instance\n\n## \u003ca name='viewer'\u003e\u003c/a\u003eBuild Your Viewer\n\nNow, let's set up your front page lobby so that surfers can visit your website and listen to or watch your live stream. I designed the front end code to be stylish and responsive, functional on both desktop and mobile browsers. There's a lot going on so I won't waste your time to discuss it. Big thanks to PicoCSS for amazing semantic CSS which is what is used to style the front end. Also using VideoJS, a free video player that handles HLS streams. Don't worry if you don't understand what I just said, just copy and paste and you'll have an amazing lobby for your surfers to visit.\n\n- You'll Need `YOUR_STREAM_KEY` and `YOUR_DOMAIN_NAME`\u003cbr /\u003e\n    - only replace the key and domain but keep the `/hls/` and `.m3u8`\u003cbr /\u003e\n      `https://YOUR_DOMAIN_NAME/hls/YOUR_STREAM_KEY.m3u8`\n\n- paste this code to create the viewer page and open it  \n    `sudo nano /var/www/html/stream.html`\n    \n- copy this code and paste it in the nano editor, make the changes to add your stream key and domain name. It has to be done twice. One for the audio and one for the video.\n\n```\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eMy Streaming Server || Better Call Jason\u003c/title\u003e\n    \u003cmeta name=\"author\" content=\"Jason Nobles\"\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\"\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css\"\u003e\n    \u003cstyle\u003e\n\n        @media only screen and (min-width: 992px) {\n            article {\n                width: 800px;\n                margin: auto;\n            }\n            video {\n                width: 700px;\n                height: 450px;\n            }\n            audio {\n                width: 700px;\n            }\n\n        }\n\n        body \u003e main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            min-height: calc(100vh - 7rem);\n            padding: 1em;\n        }\n\n        article {\n            overflow: hidden;\n            text-align: center;\n        }\n\n\n        @media only screen and (max-width: 768px) {\n\n            video {\n                width: 100%;\n                height: auto;\n            }\n            audio {\n                width: 100%;\n            }\n        }\n\n\n    \u003c/style\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n\n\u003cmain\u003e\n\n    \u003cnav\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003cstrong\u003ebcj.one/live\u003c/strong\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/nav\u003e\n\n    \u003carticle\u003e\n        \u003cdiv\u003e\n            \u003chgroup\u003e\n                \u003ch1\u003eMy Streaming Server\u003c/h1\u003e\n                \u003ch2\u003eVideo\u003c/h2\u003e\n            \u003c/hgroup\u003e\n            \u003clink href=\"https://vjs.zencdn.net/8.5.2/video-js.css\" rel=\"stylesheet\" /\u003e\n            \u003cscript src=\"https://vjs.zencdn.net/8.5.2/video.min.js\"\u003e\u003c/script\u003e\n            \u003cdiv data-vjs-player\u003e\n                \u003cvideo id=\"my_video_1\"\n                       class=\"video-js vjs-default-skin vjs-fluid vjs-16-9 vjs-big-play-centered\"\n                       controls\n                       preload='auto'\n                       data-setup='{}'\u003e\n                    \u003csource src=\"https://YOUR_DOMAIN_NAME/hls/YOUR_STREAM_KEY.m3u8\" type=\"application/x-mpegURL\"\u003e\n                \u003c/video\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n        \u003cbr\u003e\n        \u003cbr\u003e\n        \u003cdiv\u003e\n            \u003chgroup\u003e\n\n                \u003ch2\u003eAudio\u003c/h2\u003e\n            \u003c/hgroup\u003e\n            \u003cdiv data-vjs-player\u003e\n                \u003caudio\n                        id=\"my_audio_1\"\n                        class=\"video-js vjs-default-skin vjs-fluid\"\n                        controls\n                        preload=\"auto\"\n                \u003e\n                    \u003csource src=\"https://YOUR_DOMAIN_NAME/hls/YOUR_STREAM_KEY.m3u8\" type=\"application/x-mpegURL\"\u003e\n                \u003c/audio\u003e\n            \u003c/div\u003e\n\n        \u003c/div\u003e\n    \u003c/article\u003e\n\u003c/main\u003e\n\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/hls.js@latest\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/videojs-contrib-hls.js@latest\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n    var player = videojs('my_video_1');\n    player.play();\n\n    var player2 = videojs('my_audio_1');\n    player2.play();\n\u003c/script\u003e\n\u003cscript\u003e\n    const themeApplier = {\n        // Config\n        darkScheme: \"dark\",\n        rootAttribute: \"data-theme\",\n\n        // Init\n        init() {\n            this.applyScheme();\n        },\n\n        // Apply dark scheme\n        applyScheme() {\n            document\n                .querySelector(\"html\")\n                .setAttribute(this.rootAttribute, this.darkScheme);\n        },\n    };\n\n    // Init\n    themeApplier.init();\n\u003c/script\u003e\n\n\u003c/body\u003e\n\n\u003c/html\u003e\n```\n- after pasting click `ctl` + `s` and then `ctl` + `x`\u003cbr /\u003e\n\n- Now create your livestream and try it out!\n\n## \u003ca name='final'\u003e\u003c/a\u003eGo Live\n\nThe last thing to do is to test the configurations. If the response says ok, then you are all set. If you run into an issue look at the errors and try to figure it out. If you need help, please reach out. Most times, errors at this stage are typos or code syntax errors. Enter the two commands below\n\n`sudo nginx -t`  \u003cbr /\u003e\n\nif everything is good and the status is okay then :\u003cbr /\u003e\n\n`sudo systemctl restart nginx` \u003cbr /\u003e\n\nThis restarts the service and you are now ready to broadcast your live stream. \n\n- for troubleshooting your stream use tcpdump to see the operation of the livestream. If you are receiving a stream to the server the command below will be overwhelmed with data, if just an empty screen then something is wrong with your set up.  \n      \n    `sudo tcpdump -i any port 1935`\u003cbr /\u003e\n  \n  press  `ctl` + `c` to exit the stream\n\n## \u003ca name='secure'\u003e\u003c/a\u003eSecure Your Stream\n\nPrevent anyone else from broadcasting to your server by making the following changes. Only deploy these changes once you have fully tested and determined the system is working as intended. \n\n- configure nginx to receive only the stream from your ip address. Get your real IP and enter it in the provided code. You cannot broadcast from behind a VPN. The entire streaming server is a VPN on its own.\u003cbr /\u003e \n    ```sudo nano /etc/nginx/nginx.conf```  \n- copy and insert this code below with the changes at the bottom of the page. Make sure to replace `YOUR_LOCAL_IP_ADDRESS` with your real IP address\u003cbr /\u003e\n\n```\nrtmp {\n    server {\n        listen 1935;\n        chunk_size 4096;\n\n        application live {\n            live on;\n            record off;\n            allow publish YOUR_LOCAL_IP_ADDRESS;\n            deny publish all;\n\n            # Setup HLS\n            hls on;\n            hls_path /mnt/hls/;\n            hls_fragment 3;\n            hls_playlist_length 60;\n            #deny play all;\n            allow play all;\n        }\n    }\n}\n```\n- after pasting click `ctl` + `s` and then `ctl` + `x`\u003cbr /\u003e\n\n- now one more time let's test our configs:\n  \n`sudo nginx -t`  \u003cbr /\u003e\n\nif everything is good and the status is okay then :\u003cbr /\u003e\n\n`sudo systemctl restart nginx` \u003cbr /\u003e\n\nThis restarts the service and you are now ready to broadcast your live stream and you are the only one that can stream to your server now. \n\n\n## \u003ca name='donate'\u003e\u003c/a\u003eDonate\n\nThis project was months in development from the idea to full execution. Once I had a fully working model I tested it repeatedly on many different compute instances. I spent weeks in tutorial preparation trying to make it as easy as possible for a novice or an expert to own their own live stream server as conveniently as possible. While I make it all look very easy to do, there are a lot of complex things involved here. From the back end to the front end, everything is built to help you succeed. If my tutorial has helped you out, please email me at everydayjason@protonmail.com and tell me about it. I can't wait to hear about your successes! And, please consider making a BTC or LTC donation below.\n\n\n[![Donate Crypto](https://nowpayments.io/images/embeds/donation-button-white.svg \"Donate Button\")](https://nowpayments.io/donation?api_key=3JB4N4H-57MME28-GXQF9CK-G61YRXR\u0026source=lk_donation\u0026medium=referral)\n\n\nThanks for your support!\n\n## \u003ca name='goodbye'\u003e\u003c/a\u003eParting Shot\n\nAnd remember as James Evan Pilato says: \u003cbr /\u003e \n`Don't Hate The Media, Become The Media!`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbetter-call-jason%2Fnginx-streaming-server-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbetter-call-jason%2Fnginx-streaming-server-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbetter-call-jason%2Fnginx-streaming-server-app/lists"}