├── .gitignore ├── VERSION ├── .dockerignore ├── circle.yml ├── documents └── examples │ ├── streaming-server-claim0-persistentvolumeclaim.yaml │ ├── streaming-consumer-claim0-persistentvolumeclaim.yaml │ ├── streaming-consumer-service.yaml │ ├── streaming-server-service.yaml │ ├── docker-compose.yml │ ├── index.html │ ├── streaming-server-deployment.yaml │ ├── streaming-consumer-deployment.yaml │ └── full_deployment.yaml ├── assets └── etc │ └── nginx │ └── nginx.conf ├── Makefile ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /mounts 2 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0-20190219 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | .gitkeep 4 | circle.yml 5 | Makefile 6 | README.md 7 | VERSION 8 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | services: 3 | - docker 4 | test: 5 | override: 6 | - docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS 7 | - make build 8 | - make test 9 | - make push 10 | -------------------------------------------------------------------------------- /documents/examples/streaming-server-claim0-persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-server-claim0 7 | name: streaming-server-claim0 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: 100Mi 14 | status: {} 15 | -------------------------------------------------------------------------------- /documents/examples/streaming-consumer-claim0-persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-consumer-claim0 7 | name: streaming-consumer-claim0 8 | spec: 9 | accessModes: 10 | - ReadOnlyMany 11 | resources: 12 | requests: 13 | storage: 100Mi 14 | status: {} 15 | -------------------------------------------------------------------------------- /documents/examples/streaming-consumer-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-consumer 7 | name: streaming-consumer 8 | spec: 9 | ports: 10 | - name: "9999" 11 | port: 9999 12 | targetPort: 8080 13 | selector: 14 | io.kompose.service: streaming-consumer 15 | status: 16 | loadBalancer: {} 17 | -------------------------------------------------------------------------------- /documents/examples/streaming-server-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-server 7 | name: streaming-server 8 | spec: 9 | ports: 10 | - name: "1935" 11 | port: 1935 12 | targetPort: 1935 13 | - name: "8080" 14 | port: 8080 15 | targetPort: 8080 16 | selector: 17 | io.kompose.service: streaming-server 18 | status: 19 | loadBalancer: {} 20 | -------------------------------------------------------------------------------- /documents/examples/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | 4 | streaming-server: 5 | build: ../.. 6 | image: codeworksio/streaming-server 7 | container_name: streaming-server 8 | volumes: 9 | - ../../mounts/var/lib/streaming:/var/lib/streaming:Z 10 | ports: 11 | - "1935:1935" 12 | - "8080:8080" 13 | 14 | streaming-consumer: 15 | image: codeworksio/nginx 16 | container_name: streaming-consumer 17 | volumes: 18 | - .:/var/www:ro 19 | ports: 20 | - "9999:8080" 21 | -------------------------------------------------------------------------------- /documents/examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Live Streaming 6 | 7 | 8 | 9 | 10 | 11 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /documents/examples/streaming-server-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-server 7 | name: streaming-server 8 | spec: 9 | replicas: 1 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | creationTimestamp: null 15 | labels: 16 | io.kompose.service: streaming-server 17 | spec: 18 | containers: 19 | - image: codeworksio/streaming-server 20 | name: streaming-server 21 | ports: 22 | - containerPort: 1935 23 | - containerPort: 8080 24 | resources: {} 25 | volumeMounts: 26 | - mountPath: /var/lib/streaming 27 | name: streaming-server-claim0 28 | restartPolicy: Always 29 | volumes: 30 | - name: streaming-server-claim0 31 | persistentVolumeClaim: 32 | claimName: streaming-server-claim0 33 | status: {} 34 | -------------------------------------------------------------------------------- /documents/examples/streaming-consumer-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-consumer 7 | name: streaming-consumer 8 | spec: 9 | replicas: 1 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | creationTimestamp: null 15 | labels: 16 | io.kompose.service: streaming-consumer 17 | spec: 18 | containers: 19 | - image: codeworksio/nginx 20 | name: streaming-consumer 21 | ports: 22 | - containerPort: 8080 23 | resources: {} 24 | volumeMounts: 25 | - mountPath: /var/www 26 | name: streaming-consumer-claim0 27 | readOnly: true 28 | restartPolicy: Always 29 | volumes: 30 | - name: streaming-consumer-claim0 31 | persistentVolumeClaim: 32 | claimName: streaming-consumer-claim0 33 | readOnly: true 34 | status: {} 35 | -------------------------------------------------------------------------------- /assets/etc/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module modules/ngx_rtmp_module.so; 2 | 3 | worker_processes auto; 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | rtmp { 9 | server { 10 | listen 1935; 11 | chunk_size 4000; 12 | application live { 13 | live on; 14 | hls on; 15 | hls_path /var/lib/streaming/hls/; 16 | hls_fragment 3s; 17 | hls_playlist_length 60s; 18 | deny play all; 19 | } 20 | } 21 | } 22 | 23 | http { 24 | sendfile off; 25 | tcp_nopush on; 26 | aio on; 27 | directio 512; 28 | default_type application/octet-stream; 29 | server { 30 | listen 8080; 31 | location / { 32 | add_header 'Cache-Control' 'no-cache'; 33 | add_header 'Access-Control-Allow-Origin' '*' always; 34 | add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; 35 | add_header 'Access-Control-Allow-Headers' 'Range'; 36 | if ($request_method = 'OPTIONS') { 37 | add_header 'Access-Control-Allow-Origin' '*'; 38 | add_header 'Access-Control-Allow-Headers' 'Range'; 39 | add_header 'Access-Control-Max-Age' 1728000; 40 | add_header 'Content-Type' 'text/plain charset=UTF-8'; 41 | add_header 'Content-Length' 0; 42 | return 204; 43 | } 44 | types { 45 | application/dash+xml mpd; 46 | application/vnd.apple.mpegurl m3u8; 47 | video/mp2t ts; 48 | } 49 | root /var/lib/streaming/; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS := $(shell cat $(realpath $(lastword $(MAKEFILE_LIST))) | grep "^[a-z]*:" | awk '{ print $$1; }' | sed 's/://g' | grep -vE 'all|help' | paste -sd "|" -) 2 | NAME := $(subst docker-,,$(shell basename $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))) 3 | IMAGE := codeworksio/$(NAME) 4 | 5 | all: help 6 | 7 | help: 8 | echo 9 | echo "Usage:" 10 | echo 11 | echo " make $(TARGETS) [APT_PROXY|APT_PROXY_SSL=ip:port]" 12 | echo 13 | 14 | build: 15 | docker build \ 16 | --build-arg APT_PROXY=$(APT_PROXY) \ 17 | --build-arg APT_PROXY_SSL=$(APT_PROXY_SSL) \ 18 | --build-arg IMAGE=$(IMAGE) \ 19 | --build-arg BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ") \ 20 | --build-arg VERSION=$(shell cat VERSION) \ 21 | --build-arg VCS_REF=$(shell git rev-parse --short HEAD) \ 22 | --build-arg VCS_URL=$(shell git config --get remote.origin.url) \ 23 | --tag $(IMAGE):$(shell cat VERSION) \ 24 | --rm . 25 | docker tag $(IMAGE):$(shell cat VERSION) $(IMAGE):latest 26 | docker rmi --force $$(docker images | grep "" | awk '{ print $$3 }') 2> /dev/null ||: 27 | 28 | start: 29 | docker run --detach --interactive --tty \ 30 | --name $(NAME) \ 31 | --hostname $(NAME) \ 32 | --env "INIT_DEBUG=true" \ 33 | --volume $(shell pwd)/mounts/var/lib/streaming:/var/lib/streaming \ 34 | --publish 1935:1935 \ 35 | --publish 8080:8080 \ 36 | --publish 8443:8443 \ 37 | $(IMAGE) 38 | 39 | stop: 40 | docker stop $(NAME) > /dev/null 2>&1 ||: 41 | docker rm $(NAME) > /dev/null 2>&1 ||: 42 | 43 | log: 44 | docker logs --follow $(NAME) 45 | 46 | test: 47 | docker run --detach --interactive --tty --name streaming-server codeworksio/streaming-server 48 | sleep 10 49 | docker ps | grep streaming-server 50 | 51 | bash: 52 | docker exec --interactive --tty \ 53 | --user root \ 54 | $(NAME) \ 55 | /bin/bash --login ||: 56 | 57 | clean: 58 | docker rmi $(IMAGE):$(shell cat VERSION) > /dev/null 2>&1 ||: 59 | docker rmi $(IMAGE):latest > /dev/null 2>&1 ||: 60 | 61 | push: 62 | docker push $(IMAGE):$(shell cat VERSION) 63 | docker push $(IMAGE):latest 64 | sleep 10 65 | curl --request POST "https://hooks.microbadger.com/images/$(IMAGE)/o6WEpIkU6QkdRAOuZ9EcPx6djOo=" 66 | 67 | .SILENT: 68 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codeworksio/nginx:1.15.8-20190219 2 | 3 | ARG APT_PROXY 4 | ARG APT_PROXY_SSL 5 | ENV NGINX_RTMP_MODULE_VERSION="1.2.1" 6 | 7 | RUN set -ex; \ 8 | \ 9 | buildDependencies="\ 10 | build-essential \ 11 | libpcre3-dev \ 12 | libssl-dev \ 13 | zlib1g-dev \ 14 | "; \ 15 | if [ -n "$APT_PROXY" ]; then echo "Acquire::http { Proxy \"http://${APT_PROXY}\"; };" > /etc/apt/apt.conf.d/00proxy; fi; \ 16 | if [ -n "$APT_PROXY_SSL" ]; then echo "Acquire::https { Proxy \"https://${APT_PROXY_SSL}\"; };" > /etc/apt/apt.conf.d/00proxy; fi; \ 17 | apt-get --yes update; \ 18 | apt-get --yes install \ 19 | $buildDependencies \ 20 | ffmpeg \ 21 | ; \ 22 | cd /tmp; \ 23 | curl -L "https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz" -o nginx-$NGINX_VERSION.tar.gz; \ 24 | tar -xf nginx-$NGINX_VERSION.tar.gz; \ 25 | curl -L "https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_MODULE_VERSION}.tar.gz" -o nginx-rtmp-module-$NGINX_RTMP_MODULE_VERSION.tar.gz; \ 26 | tar -xf nginx-rtmp-module-$NGINX_RTMP_MODULE_VERSION.tar.gz; \ 27 | \ 28 | cd /tmp/nginx-$NGINX_VERSION; \ 29 | ./configure \ 30 | $(nginx -V 2>&1 | grep 'configure arguments:' | sed 's/configure arguments://g') \ 31 | --add-dynamic-module=/tmp/nginx-rtmp-module-$NGINX_RTMP_MODULE_VERSION; \ 32 | make modules; \ 33 | mkdir -p /usr/local/nginx/modules; \ 34 | cp -v objs/ngx_rtmp_module.so /usr/local/nginx/modules; \ 35 | \ 36 | mkdir -p \ 37 | /var/lib/streaming/hls \ 38 | /var/lib/streaming/dash; \ 39 | chown -R $SYSTEM_USER:$SYSTEM_USER \ 40 | /usr/local/nginx/modules \ 41 | /var/lib/streaming; \ 42 | \ 43 | apt-get purge --yes --auto-remove $buildDependencies; \ 44 | rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/*; \ 45 | rm -f /etc/apt/apt.conf.d/00proxy 46 | 47 | COPY assets/ / 48 | 49 | VOLUME [ "/var/lib/streaming" ] 50 | EXPOSE 1935 8080 8443 51 | CMD [ "nginx", "-g", "daemon off;" ] 52 | 53 | ### METADATA ################################################################### 54 | 55 | ARG IMAGE 56 | ARG BUILD_DATE 57 | ARG VERSION 58 | ARG VCS_REF 59 | ARG VCS_URL 60 | LABEL \ 61 | org.label-schema.name=$IMAGE \ 62 | org.label-schema.build-date=$BUILD_DATE \ 63 | org.label-schema.version=$VERSION \ 64 | org.label-schema.vcs-ref=$VCS_REF \ 65 | org.label-schema.vcs-url=$VCS_URL \ 66 | org.label-schema.schema-version="1.0" 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Circle CI](https://circleci.com/gh/codeworksio/docker-streaming-server.svg?style=shield "CircleCI")](https://circleci.com/gh/codeworksio/docker-streaming-server) [![Size](https://images.microbadger.com/badges/image/codeworksio/streaming-server.svg)](http://microbadger.com/images/codeworksio/streaming-server) [![Version](https://images.microbadger.com/badges/version/codeworksio/streaming-server.svg)](http://microbadger.com/images/codeworksio/streaming-server) [![Commit](https://images.microbadger.com/badges/commit/codeworksio/streaming-server.svg)](http://microbadger.com/images/codeworksio/streaming-server) [![Docker Hub](https://img.shields.io/docker/pulls/codeworksio/streaming-server.svg)](https://hub.docker.com/r/codeworksio/streaming-server/) 2 | 3 | Docker Streaming Server 4 | ======================= 5 | 6 | A robust way of streaming media content live using the [NGINX](https://nginx.org/) web server and its [RTMP](https://github.com/tiangolo/nginx-rtmp-docker) module. 7 | 8 | Installation 9 | ------------ 10 | 11 | Builds of the image are available on [Docker Hub](https://hub.docker.com/r/codeworksio/streaming-server/). 12 | 13 | docker pull codeworksio/streaming-server 14 | 15 | Alternatively you can build the image yourself. 16 | 17 | docker build --tag codeworksio/streaming-server \ 18 | github.com/codeworksio/docker-streaming-server 19 | 20 | Quickstart 21 | ---------- 22 | 23 | Start container using: 24 | 25 | docker run --detach --restart always \ 26 | --name streaming-server \ 27 | --hostname streaming-server \ 28 | --publish 1935:1935 \ 29 | --publish 8080:8080 \ 30 | --publish 8443:8443 \ 31 | codeworksio/streaming-server 32 | 33 | Example 34 | ------- 35 | 36 | 1. Start the streaming server and consumer from the command line 37 | 38 | ```bash 39 | cd ./documents/examples 40 | docker-compose up -d 41 | ``` 42 | 43 | 2. Use [Open Broadcaster Software](https://obsproject.com/) to stream your content 44 | 45 | * Add media source `Sources` > `+` > `Video Capture Device` 46 | * Configure streaming server `Controls` > `Settings` > `Stream` 47 | - Stream type: `Custom Streaming Server` 48 | - URL: `rtmp://localhost/live` 49 | - Stream key: `test` 50 | * Press `Start Streaming` button 51 | 52 | 3. Go to `http://localhost:9999` URL address in your browser to view the media live. 53 | 54 | See 55 | --- 56 | 57 | * [Open Broadcaster Software post](https://obsproject.com/forum/resources/how-to-set-up-your-own-private-streaming-server-server-using-nginx.50/) 58 | -------------------------------------------------------------------------------- /documents/examples/full_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: streaming-server 7 | name: streaming-server 8 | spec: 9 | replicas: 1 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | creationTimestamp: null 15 | labels: 16 | io.kompose.service: streaming-server 17 | spec: 18 | containers: 19 | - image: codeworksio/streaming-server 20 | name: streaming-server 21 | ports: 22 | - containerPort: 1935 23 | - containerPort: 8080 24 | resources: {} 25 | volumeMounts: 26 | - mountPath: /var/lib/streaming 27 | name: streaming-server-claim0 28 | restartPolicy: Always 29 | volumes: 30 | - name: streaming-server-claim0 31 | persistentVolumeClaim: 32 | claimName: streaming-server-claim0 33 | status: {} 34 | 35 | --- 36 | apiVersion: v1 37 | kind: Service 38 | metadata: 39 | creationTimestamp: null 40 | labels: 41 | io.kompose.service: streaming-server 42 | name: streaming-server 43 | spec: 44 | ports: 45 | - port: 1935 46 | targetPort: 1935 47 | - port: 8080 48 | targetPort: 8080 49 | selector: 50 | io.kompose.service: streaming-server 51 | status: 52 | loadBalancer: {} 53 | 54 | --- 55 | apiVersion: v1 56 | kind: PersistentVolumeClaim 57 | metadata: 58 | creationTimestamp: null 59 | labels: 60 | io.kompose.service: streaming-server-claim0 61 | name: streaming-server-claim0 62 | spec: 63 | accessModes: 64 | - ReadWriteOnce 65 | resources: 66 | requests: 67 | storage: 100Mi 68 | status: {} 69 | 70 | --- 71 | apiVersion: extensions/v1beta1 72 | kind: Deployment 73 | metadata: 74 | creationTimestamp: null 75 | labels: 76 | io.kompose.service: streaming-consumer 77 | name: streaming-consumer 78 | spec: 79 | replicas: 1 80 | strategy: 81 | type: Recreate 82 | template: 83 | metadata: 84 | creationTimestamp: null 85 | labels: 86 | io.kompose.service: streaming-consumer 87 | spec: 88 | containers: 89 | - image: codeworksio/nginx 90 | name: streaming-consumer 91 | ports: 92 | - containerPort: 8080 93 | resources: {} 94 | volumeMounts: 95 | - mountPath: /var/www 96 | name: streaming-consumer-claim0 97 | readOnly: true 98 | restartPolicy: Always 99 | volumes: 100 | - name: streaming-consumer-claim0 101 | persistentVolumeClaim: 102 | claimName: streaming-consumer-claim0 103 | readOnly: true 104 | status: {} 105 | 106 | --- 107 | apiVersion: v1 108 | kind: Service 109 | metadata: 110 | creationTimestamp: null 111 | labels: 112 | io.kompose.service: streaming-consumer 113 | name: streaming-consumer 114 | spec: 115 | ports: 116 | - port: 9999 117 | targetPort: 8080 118 | selector: 119 | io.kompose.service: streaming-consumer 120 | status: 121 | loadBalancer: {} 122 | 123 | --- 124 | apiVersion: v1 125 | kind: PersistentVolumeClaim 126 | metadata: 127 | creationTimestamp: null 128 | labels: 129 | io.kompose.service: streaming-consumer-claim0 130 | name: streaming-consumer-claim0 131 | spec: 132 | accessModes: 133 | - ReadOnlyMany 134 | resources: 135 | requests: 136 | storage: 100Mi 137 | status: {} --------------------------------------------------------------------------------