├── .github ├── actions │ ├── deploy-almalinux-8 │ │ └── action.yml │ ├── deploy-almalinux-9 │ │ └── action.yml │ ├── deploy-centos-8 │ │ └── action.yml │ ├── deploy-debian-11 │ │ └── action.yml │ ├── deploy-debian-12 │ │ └── action.yml │ ├── deploy-rockylinux-8 │ │ └── action.yml │ └── deploy-rockylinux-9 │ │ └── action.yml └── workflows │ ├── 24x7-test1.yml │ ├── almalinux.yml │ ├── ant-media-server-docker-multi-platform.yml │ ├── antmedia-cf-template-validation-test.yml │ ├── centos8.yml │ ├── check-marketplace-jwt-token.yml │ ├── debian.yml │ ├── docker-supervisor.yml │ ├── install-dockerfile-and-check-ssl.yml │ ├── install-latest-snapshot-to-ubuntu-22-04.yml │ ├── install-latest-snapshot-to-ubuntu-24-04.yml │ ├── install-latest-to-ubuntu-22-04.yml │ ├── install-latest-to-ubuntu-24-04.yml │ ├── mongodb-install-test.yml │ ├── rockylinux.yml │ ├── samples.yml │ ├── uninstall-ams.yml │ └── upgrade-sh-validation.yml ├── .gitignore ├── 24x7-testing ├── .gitkeep └── 24x7-test1.py ├── Dockerfile ├── README.md ├── Selenium └── antmedia-samples.py ├── ams_release.sh ├── aws └── ant_media_server_aws_cluster_update.py ├── azure-arm-template └── antmedia-azure-autoscale.yaml ├── cloudformation ├── antmedia-aws-autoscale-remote_db-template.yaml ├── antmedia-aws-autoscale-template.yaml ├── antmedia-aws-autoscale-with-monitoring-tool.yaml ├── antmedia-aws-monitoring-tool.yaml ├── aws-streaming-wizard │ ├── index.php │ ├── template-custom-cert.yaml │ └── template.yaml ├── cf-snippets │ ├── edge-launch-config.yaml │ ├── edge.yaml │ ├── mongodb.yaml │ ├── monitor.yaml │ ├── origin-launch-config.yaml │ ├── origin.yaml │ └── output.yaml ├── cloudformation_set_username_password.sh ├── graylog.yaml ├── kafka_2.13-2.8.1.tgz ├── turnserver.yaml └── wavelength │ ├── ams-wavelength-autoscale.yaml │ ├── ams-wavelength-standalone.yaml │ ├── stunserver.yaml │ └── wavelength-vpc.yaml ├── docker ├── Dockerfile_Process ├── Dockerfile_RockyLinux └── docker-compose.yml ├── easy_ssl.sh ├── gcp-jinja-template ├── antmedia-firewall-template.jinja ├── antmedia-instance-group-template.jinja ├── antmedia-instance-template.jinja ├── antmedia-loadbalancer-template.jinja ├── antmedia-mongodb-template.jinja ├── antmedia-vpc-template.jinja ├── antmedia.jinja ├── antmedia.yaml └── backend.jinja ├── init.sh ├── install-monitoring-tools.sh ├── install_ant-media-server.sh ├── install_graylog.sh ├── install_mongodb.sh ├── install_turn-server.sh ├── kubernetes ├── ams-k8s-deployment-edge.yaml ├── ams-k8s-deployment-origin.yaml ├── ams-k8s-deployment.yaml ├── ams-k8s-hpa-edge.yaml ├── ams-k8s-hpa-origin.yaml ├── ams-k8s-hpa.yaml ├── ams-k8s-ingress-edge.yaml ├── ams-k8s-ingress-origin.yaml ├── ams-k8s-ingress.yaml ├── ams-k8s-issuer-production.yaml ├── ams-k8s-issuer-staging.yaml ├── ams-k8s-mongodb.yaml ├── ams-k8s-rtmp.yaml └── ams-with-turn-server │ ├── ams-k8s-coturn.yaml │ ├── ams-k8s-deployment-edge.yaml │ ├── ams-k8s-deployment-origin.yaml │ ├── ams-k8s-hpa-edge.yaml │ ├── ams-k8s-hpa-origin.yaml │ ├── ams-k8s-ingress-edge.yaml │ ├── ams-k8s-ingress-origin.yaml │ ├── ams-k8s-mongodb.yaml │ └── ams-k8s-rtmp.yaml ├── lambda_functions ├── enable_ssl_check_domains.py ├── enable_ssl_delete_domains.py └── enable_ssl_verify_domains.py ├── load-testing ├── .gitkeep ├── hls_players.sh ├── rtmp_publisher.sh └── srt_publishers.sh ├── monitor ├── ams-new-relic-dashboard.json ├── antmediaserver.json ├── datasource.json ├── fluentbit_values.yaml └── install-graylog.sh ├── nginx ├── README.md ├── antmedia-cluster-check.service ├── install_and_configure_nginx.sh ├── nginx-auto-scale.sh └── nginx.conf ├── pre_init.sh ├── prepare_changelog.sh └── vod_transcode.sh /.github/actions/deploy-almalinux-8/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on AlmaLinux 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | yum -y install wget which findutils which crontabs unzip 12 | curl -L -o ant-media-server-community.zip https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.11.3/ant-media-server-community-2.11.3.zip 13 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 14 | /usr/local/antmedia/antmedia start 15 | sleep 30 16 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 17 | echo "LiveApp started log does not exist. Check the logs above" 18 | exit 1; 19 | fi; 20 | -------------------------------------------------------------------------------- /.github/actions/deploy-almalinux-9/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on AlmaLinux 9 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | yum -y install wget which findutils which crontabs unzip 11 | yum -y install wget which findutils which crontabs unzip 12 | curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 13 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 14 | /usr/local/antmedia/antmedia start 15 | sleep 40 16 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 17 | echo "LiveApp started log does not exist. Check the logs above" 18 | exit 1; 19 | fi; 20 | -------------------------------------------------------------------------------- /.github/actions/deploy-centos-8/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on Centos 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 12 | sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 13 | yum -y install wget which findutils which crontabs unzip 14 | curl -L -o ant-media-server-community.zip https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.11.3/ant-media-server-community-2.11.3.zip 15 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 16 | /usr/local/antmedia/antmedia start 17 | sleep 30 18 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 19 | echo "LiveApp started log does not exist. Check the logs above" 20 | exit 1; 21 | fi; 22 | -------------------------------------------------------------------------------- /.github/actions/deploy-debian-11/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on Debian 11 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | apt-get update 11 | apt-get -y install wget findutils unzip curl 12 | curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 13 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 14 | /usr/local/antmedia/antmedia start 15 | sleep 40 16 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 17 | echo "LiveApp started log does not exist. Check the logs above" 18 | exit 1; 19 | fi; 20 | -------------------------------------------------------------------------------- /.github/actions/deploy-debian-12/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on Debian 12 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | apt-get update 11 | apt-get -y install wget findutils unzip curl 12 | curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 13 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 14 | /usr/local/antmedia/antmedia start 15 | sleep 40 16 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 17 | echo "LiveApp started log does not exist. Check the logs above" 18 | exit 1; 19 | fi; 20 | -------------------------------------------------------------------------------- /.github/actions/deploy-rockylinux-8/action.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Deploy on RockyLinux 3 | runs: 4 | using: composite 5 | steps: 6 | - name: Checkout repository 7 | uses: actions/checkout@v3 8 | - name: Install Ant Media Server 9 | shell: bash 10 | run: | 11 | echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 12 | yum -y install wget which findutils which crontabs unzip 13 | curl -L -o ant-media-server-community.zip https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.11.3/ant-media-server-community-2.11.3.zip 14 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 15 | /usr/local/antmedia/antmedia start 16 | sleep 30 17 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 18 | echo "LiveApp started log does not exist. Check the logs above" 19 | exit 1; 20 | fi; 21 | -------------------------------------------------------------------------------- /.github/actions/deploy-rockylinux-9/action.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on RockyLinux 9 2 | runs: 3 | using: composite 4 | steps: 5 | - name: Checkout repository 6 | uses: actions/checkout@v3 7 | - name: Install Ant Media Server 8 | shell: bash 9 | run: | 10 | yum -y install wget which findutils which crontabs unzip 11 | curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 12 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false 13 | /usr/local/antmedia/antmedia start 14 | sleep 40 15 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 16 | echo "LiveApp started log does not exist. Check the logs above" 17 | exit 1; 18 | fi; 19 | -------------------------------------------------------------------------------- /.github/workflows/24x7-test1.yml: -------------------------------------------------------------------------------- 1 | name: Python 24x7 script 2 | 3 | on: 4 | schedule: 5 | - cron: '*/5 * * * *' 6 | 7 | jobs: 8 | run-selenium: 9 | runs-on: ubuntu-latest 10 | env: 11 | WEBHOOK_URL: ${{ secrets.WEBHOOK }} 12 | SERVER_IP: ${{ secrets.SERVER_IP }} 13 | USERNAME: ${{ secrets.USERNAME }} 14 | PASSWORD: ${{ secrets.PASSWORD }} 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v3 19 | 20 | - name: Set up Python 3 21 | uses: actions/setup-python@v3 22 | with: 23 | python-version: 3.x 24 | 25 | - name: Install dependencies 26 | run: | 27 | pip install requests 28 | pip install paramiko 29 | 30 | - name: Run staging script 31 | run: | 32 | python 24x7-testing/24x7-test1.py 33 | -------------------------------------------------------------------------------- /.github/workflows/almalinux.yml: -------------------------------------------------------------------------------- 1 | name: AlmaLinux 2 | on: [push] 3 | 4 | jobs: 5 | Almalinux9: 6 | runs-on: ubuntu-24.04 7 | container: almalinux:9 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: ./.github/actions/deploy-almalinux-9 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/ant-media-server-docker-multi-platform.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD for Docker Images - Ant Media Server (Ubuntu & Rocky Linux) 2 | 3 | on: [push] 4 | 5 | jobs: 6 | ams_ubuntu_docker_test: 7 | runs-on: ubuntu-latest 8 | env: 9 | BRANCH_NAME: ${{ github.ref_name }} 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v3 13 | 14 | - name: Download the latest version of Ant Media Server 15 | run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 16 | 17 | - name: Download Dockerfile 18 | run: wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/$BRANCH_NAME/docker/Dockerfile_Process -O Dockerfile 19 | 20 | - name: Build Docker image 21 | run: docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip --build-arg BranchName=$BRANCH_NAME . 22 | 23 | - name: Run the image 24 | run: docker run -d -p 5080:5080 --name antmediaserver antmediaserver 25 | 26 | - name: Check Ant Media Server health with a timeout 27 | run: | 28 | timeout=120 29 | start_time=$(date +%s) 30 | until wget http://localhost:5080 -O index.html; do 31 | current_time=$(date +%s) 32 | elapsed_time=$((current_time - start_time)) 33 | 34 | if [ $elapsed_time -gt $timeout ]; then 35 | echo "Timeout reached. Ant Media Server did not start within $timeout seconds." 36 | exit 1 37 | fi 38 | 39 | echo "Waiting for Ant Media Server to start..." 40 | sleep 10 41 | done 42 | 43 | - name: Stop and remove the container 44 | run: docker stop antmediaserver && docker rm antmediaserver 45 | 46 | ams_rockylinux_docker_test: 47 | runs-on: ubuntu-latest 48 | env: 49 | BRANCH_NAME: ${{ github.ref_name }} 50 | steps: 51 | - name: Checkout code 52 | uses: actions/checkout@v3 53 | 54 | - name: Download the latest version of Ant Media Server 55 | run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 56 | 57 | - name: Download Dockerfile 58 | run: | 59 | echo "Building Docker image with branch: $BRANCH_NAME" 60 | wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/$BRANCH_NAME/docker/Dockerfile_RockyLinux -O Dockerfile 61 | 62 | - name: Build Docker image 63 | run: | 64 | echo "Building Docker image with branch: $BRANCH_NAME" 65 | docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip --build-arg BranchName=$BRANCH_NAME . 66 | 67 | - name: Run the image 68 | run: docker run -d -p 5080:5080 --name antmediaserver antmediaserver 69 | 70 | - name: Check Ant Media Server health with a timeout 71 | run: | 72 | timeout=120 73 | start_time=$(date +%s) 74 | until wget http://localhost:5080 -O index.html; do 75 | current_time=$(date +%s) 76 | elapsed_time=$((current_time - start_time)) 77 | 78 | if [ $elapsed_time -gt $timeout ]; then 79 | echo "Timeout reached. Ant Media Server did not start within $timeout seconds." 80 | exit 1 81 | fi 82 | 83 | echo "Waiting for Ant Media Server to start..." 84 | sleep 10 85 | done 86 | 87 | - name: Stop and remove the container 88 | run: docker stop antmediaserver && docker rm antmediaserver 89 | -------------------------------------------------------------------------------- /.github/workflows/antmedia-cf-template-validation-test.yml: -------------------------------------------------------------------------------- 1 | name: Ant Media Server Cloudformation Deployment 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 1' 6 | 7 | jobs: 8 | deploy_cf_template: 9 | runs-on: ubuntu-latest 10 | 11 | env: 12 | AWS_REGION: eu-west-2 13 | STACK_NAME: cf-automation-test-stack 14 | ORIGIN_INSTANCE_TYPE: t2.large 15 | EDGE_INSTANCE_TYPE: t2.large 16 | MONGO_INSTANCE_TYPE: c5.large 17 | TEMPLATE_FILE: ${{ github.workspace }}/cloudformation/antmedia-aws-autoscale-template.yaml 18 | 19 | steps: 20 | - name: Checkout Repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Configure AWS Credentials 24 | uses: aws-actions/configure-aws-credentials@v1 25 | with: 26 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 27 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 28 | aws-region: ${{ env.AWS_REGION }} 29 | 30 | - name: Validate CloudFormation Template 31 | run: | 32 | aws cloudformation validate-template --template-body file://${{ env.TEMPLATE_FILE }} 33 | 34 | - name: Deploy Stack 35 | run: | 36 | aws cloudformation create-stack \ 37 | --stack-name ${{ env.STACK_NAME }} \ 38 | --template-body file://${{ env.TEMPLATE_FILE }} \ 39 | --parameters ParameterKey=Email,ParameterValue=test@antmedia.io \ 40 | ParameterKey=KeyName,ParameterValue=${{ secrets.KEY_NAME }} \ 41 | ParameterKey=OriginInstanceType,ParameterValue=${{ env.ORIGIN_INSTANCE_TYPE }} \ 42 | ParameterKey=EdgeInstanceType,ParameterValue=${{ env.EDGE_INSTANCE_TYPE }} \ 43 | ParameterKey=MongoDBInstanceType,ParameterValue=${{ env.MONGO_INSTANCE_TYPE }} \ 44 | ParameterKey=LoadBalancerCertificateArn,ParameterValue=${{ secrets.SSL_CERTIFICATE_ARN }} \ 45 | ParameterKey=AntMediaEdgeCapacity,ParameterValue=1 \ 46 | --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ 47 | --region ${{ env.AWS_REGION }} 48 | timeout=$((SECONDS+420)) 49 | while [ $SECONDS -lt $timeout ]; do 50 | sleep 10 51 | stack_status=$(aws cloudformation describe-stacks --stack-name ${{ env.STACK_NAME }} --query 'Stacks[0].StackStatus' --output text 2>&1) 52 | if [ "$stack_status" == "CREATE_COMPLETE" ]; then 53 | echo "Stack creation completed successfully." 54 | break 55 | elif [ "$stack_status" == "ROLLBACK_COMPLETE" ] || [ "$stack_status" == "CREATE_FAILED" ]; then 56 | echo "Stack creation failed or rolled back." 57 | exit 1 58 | fi 59 | done 60 | 61 | - name: Display Stack Outputs 62 | run: | 63 | outputs=$(aws cloudformation describe-stacks --stack-name ${{ env.STACK_NAME }} --query 'Stacks[0].Outputs' 2>&1) 64 | status=$? 65 | 66 | if [ $status -ne 0 ]; then 67 | echo "Failed to describe stack: $outputs" 68 | exit 1 69 | elif [ "$outputs" == "null" ]; then 70 | echo "Stack Outputs are null. Deployment failed." 71 | exit 1 72 | else 73 | echo "Stack Outputs: $outputs" 74 | fi 75 | - name: Delete Stack 76 | if: ${{ always() }} 77 | run: | 78 | aws cloudformation delete-stack --stack-name ${{ env.STACK_NAME }} 79 | aws cloudformation wait stack-delete-complete --stack-name ${{ env.STACK_NAME }} 80 | 81 | - name: Send Slack Notification on Failure 82 | if: failure() 83 | uses: slackapi/slack-github-action@v2.0.0 84 | with: 85 | method: chat.postMessage 86 | token: ${{ secrets.SLACK_BOT_TOKEN }} 87 | payload: | 88 | channel: ${{ secrets.SLACK_CHANNEL_ID }} 89 | text: "<@murat> CloudFormation deployment failed! :x:\nWorkflow: ${{ github.workflow }}\nJob: ${{ github.job }}\nCheck the logs: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" 90 | 91 | - name: Send Slack Notification on Success 92 | if: success() 93 | uses: slackapi/slack-github-action@v2.0.0 94 | with: 95 | method: chat.postMessage 96 | token: ${{ secrets.SLACK_BOT_TOKEN }} 97 | payload: | 98 | channel: ${{ secrets.SLACK_CHANNEL_ID }} 99 | text: "CloudFormation deployment completed successfully! :white_check_mark:\nWorkflow: ${{ github.workflow }}\nJob: ${{ github.job }}" 100 | -------------------------------------------------------------------------------- /.github/workflows/centos8.yml: -------------------------------------------------------------------------------- 1 | name: Centos 2 | on: [push] 3 | 4 | jobs: 5 | Centos8: 6 | runs-on: ubuntu-24.04 7 | container: centos:8 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: ./.github/actions/deploy-centos-8 -------------------------------------------------------------------------------- /.github/workflows/check-marketplace-jwt-token.yml: -------------------------------------------------------------------------------- 1 | name: Marketplace SSL Test 2 | 3 | #run tests on schedule because we don't want to generate a subdomain everytime 4 | on: 5 | schedule: 6 | - cron: '0 0 * * 1' 7 | 8 | 9 | 10 | jobs: 11 | run_build: 12 | name: Marketplace SSL Test 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout Repository 17 | uses: actions/checkout@v2 18 | 19 | - name: Run enable_ssl.sh for marketplace 20 | uses: appleboy/ssh-action@master 21 | with: 22 | #OVH_REMOTE_HOST has marketplace version deployed 23 | host: ${{ secrets.OVH_REMOTE_HOST }} 24 | username: ${{ secrets.OVH_REMOTE_USERNAME }} 25 | key: ${{ secrets.OVH_SSH_PRIVATE_KEY }} 26 | port: ${{ secrets.OVH_REMOTE_PORT }} 27 | # If the version is not marketplace, following enable_ssl.sh script fails 28 | script: | 29 | SECRET_KEY=$(openssl rand -base64 32 | head -c 32) 30 | sudo sed -i "/^server.jwtServerControlEnabled=/s|.*|server.jwtServerControlEnabled=true|" /usr/local/antmedia/conf/red5.properties 31 | sudo sed -i "/^server.jwtServerSecretKey=/s|.*|server.jwtServerSecretKey=$SECRET_KEY|" /usr/local/antmedia/conf/red5.properties 32 | sudo service antmedia restart 33 | sleep 20 34 | OUTPUT=$(sudo bash /usr/local/antmedia/enable_ssl.sh) 35 | echo "OUTPUT -> $OUTPUT"; 36 | HTTPS_URL=$(echo "$OUTPUT" | grep 'You can use this url: '| grep -o 'https://[^ ]*') 37 | echo "HTTPS_URL -> $HTTPS_URL" 38 | sleep 20 39 | status_code=$(curl -o /dev/null -s -I -w "%{http_code}" "$HTTPS_URL") 40 | if [ "$status_code" -eq 200 ]; then 41 | echo "URL($HTTPS_URL) is working: $status_code" 42 | else 43 | echo "URL($HTTPS_URL) is not working: $status_code" 44 | exit 1; 45 | fi 46 | 47 | 48 | - name: Run enable_ssl.sh for existing domain 49 | uses: appleboy/ssh-action@master 50 | with: 51 | host: ${{ secrets.OVH_REMOTE_HOST }} 52 | username: ${{ secrets.OVH_REMOTE_USERNAME }} 53 | key: ${{ secrets.OVH_SSH_PRIVATE_KEY }} 54 | port: ${{ secrets.OVH_REMOTE_PORT }} 55 | #restore the old domain to not encounter any issue 56 | script: | 57 | sudo bash /usr/local/antmedia/enable_ssl.sh -d ${{ secrets.OVH_REMOTE_HOST }} 58 | -------------------------------------------------------------------------------- /.github/workflows/debian.yml: -------------------------------------------------------------------------------- 1 | name: Debian 2 | on: [push] 3 | 4 | jobs: 5 | Debian11: 6 | runs-on: ubuntu-24.04 7 | container: debian:11 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: ./.github/actions/deploy-debian-11 11 | Debian12: 12 | runs-on: ubuntu-24.04 13 | container: debian:12 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: ./.github/actions/deploy-debian-12 17 | -------------------------------------------------------------------------------- /.github/workflows/docker-supervisor.yml: -------------------------------------------------------------------------------- 1 | name: Test Dockerfile with supervisor and without supervisor 2 | 3 | on: [push] 4 | env: 5 | DEBUG: true 6 | 7 | jobs: 8 | test-docker-builds: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | supervisor: [ true, false] 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up Docker Buildx 19 | uses: docker/setup-buildx-action@v3 20 | 21 | - name: Download the latest version of Ant Media Server 22 | run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 23 | 24 | - name: Build with Supervisor=${{ matrix.supervisor }} 25 | run: | 26 | docker build -f docker/Dockerfile_Process \ 27 | --build-arg UseSupervisor=${{ matrix.supervisor }} \ 28 | --build-arg AntMediaServer=ant-media-server-community.zip \ 29 | -t antmedia:${{ matrix.supervisor }} . 30 | 31 | - name: Test Container (Supervisor=${{ matrix.supervisor }}) 32 | run: | 33 | docker images 34 | export LICENSE_KEY="test-test" 35 | docker run -d -p 5080:5080 --name antmedia-${{ matrix.supervisor }} antmedia:${{ matrix.supervisor }} -l $LICENSE_KEY 36 | docker ps -a 37 | docker logs antmedia-${{ matrix.supervisor }} 38 | sleep 30 39 | docker ps 40 | AMS_PID=$(docker exec antmedia-${{ matrix.supervisor }} pgrep -f "antmedia") 41 | if [ "${{ matrix.supervisor }}" = "true" ]; then 42 | # With supervisor: AMS should NOT run with PID 1 43 | if [ "$AMS_PID" = "1" ]; then 44 | echo "Error: Ant Media Server is running with PID 1 when supervisor is enabled" 45 | docker logs antmedia-${{ matrix.supervisor }} 46 | exit 1 47 | else 48 | echo "Success: Ant Media Server is running with PID $AMS_PID (with supervisor)" 49 | # we dont check license key when supervisor is enabled because passing command line parameters has not been supported yet 50 | fi 51 | else 52 | # Without supervisor: AMS should run with PID 1 53 | if [ "$AMS_PID" = "1" ]; then 54 | echo "Success: Ant Media Server is running with PID 1 (without supervisor)" 55 | AMS_LICENSE_KEY=$(docker exec antmedia-${{ matrix.supervisor }} cat /usr/local/antmedia/conf/red5.properties | grep "server.licence_key" | cut -d'=' -f2) 56 | echo "AMS_LICENSE_KEY: $AMS_LICENSE_KEY" 57 | #check if the license key is set correctly. It validates that docker file accepts the parameters from command line 58 | 59 | if [ "$AMS_LICENSE_KEY" != "$LICENSE_KEY" ]; then 60 | echo "Error: License key mismatch" 61 | exit 1 62 | fi 63 | else 64 | echo "Error: Ant Media Server is not running with PID 1 when supervisor is disabled" 65 | docker logs antmedia-${{ matrix.supervisor }} 66 | exit 1 67 | fi 68 | fi 69 | 70 | # Additional validation: Check if supervisor is running when enabled 71 | if [ "${{ matrix.supervisor }}" = "true" ]; then 72 | SUPERVISOR_RUNNING=$(docker exec antmedia-${{ matrix.supervisor }} pgrep -f "supervisord" || echo "") 73 | if [ -z "$SUPERVISOR_RUNNING" ]; then 74 | echo "Error: Supervisor process not found when it should be enabled" 75 | exit 1 76 | fi 77 | fi 78 | 79 | - name: Check Ant Media Server health with a timeout 80 | run: | 81 | timeout=120 82 | start_time=$(date +%s) 83 | until wget http://localhost:5080 -O index.html; do 84 | current_time=$(date +%s) 85 | elapsed_time=$((current_time - start_time)) 86 | 87 | if [ $elapsed_time -gt $timeout ]; then 88 | echo "Timeout reached. Ant Media Server did not start within $timeout seconds." 89 | exit 1 90 | fi 91 | 92 | echo "Waiting for Ant Media Server to start..." 93 | sleep 10 94 | done 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /.github/workflows/install-dockerfile-and-check-ssl.yml: -------------------------------------------------------------------------------- 1 | name: Docker Build and Test 2 | 3 | on: 4 | # [push] 5 | workflow_dispatch: 6 | schedule: 7 | - cron: '0 0 */5 * *' 8 | 9 | jobs: 10 | build: 11 | runs-on: self-hosted 12 | 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v2 16 | 17 | - name: Show current branch 18 | run: echo "Current branch is ${{ github.event.inputs.branch_name }}" 19 | 20 | - name: stop the AMS service 21 | run: sudo systemctl stop antmedia 22 | 23 | - name: Run Docker service 24 | run: sudo systemctl restart docker 25 | 26 | - name: Build Docker image 27 | run: docker build -f docker/Dockerfile_Process --network=host -t antmediaserver --build-arg LicenseKey="${{ secrets.ENTERPRISE_LICENSE }}" . 28 | 29 | - name: Run Docker container 30 | run: docker run --restart=always -d --name antmedia --network=host -it antmediaserver 31 | 32 | - name: Check if SSL is enabled or not 33 | run: | 34 | set -e 35 | if docker exec antmedia curl -f https://${{ secrets.CI_SSL_TEST_DOMAIN }}:5443; then 36 | echo "Endpoint is reachable." 37 | exit 1 38 | else 39 | echo "Endpoint is not reachable, but continuing workflow." 40 | fi 41 | 42 | # - name: Clone branch 43 | # run: | 44 | # git clone --depth=1 -b ${{ github.event.inputs.branch_name }} https://github.com/ant-media/Ant-Media-Server.git || git clone --depth=1 https://github.com/ant-media/Ant-Media-Server.git 45 | 46 | - name: Download enable_ssl.sh inside container 47 | run: docker exec antmedia wget -O /usr/local/antmedia/enable_ssl.sh https://raw.githubusercontent.com/ant-media/Ant-Media-Server/master/src/main/server/enable_ssl.sh 48 | 49 | # - name: Copy enable_ssl.sh from cloned branch to container 50 | # run: docker cp Ant-Media-Server/src/main/server/enable_ssl.sh antmedia:/usr/local/antmedia/enable_ssl.sh 51 | 52 | - name: Run enable_ssl.sh inside container 53 | run: docker exec antmedia bash /usr/local/antmedia/enable_ssl.sh -d ${{ secrets.CI_SSL_TEST_DOMAIN }} 54 | 55 | - name: Verify container is running 56 | run: | 57 | sleep 20 58 | docker ps -f name=antmedia 59 | if [ $(docker ps -f name=antmedia --format '{{.Names}}') != "antmedia" ]; then 60 | echo "Container is not running" 61 | exit 1 62 | fi 63 | 64 | - name: Test application 65 | run: | 66 | docker exec antmedia curl -f https://${{ secrets.CI_SSL_TEST_DOMAIN }}:5443 67 | - name: Stop and remove container 68 | if: ${{ always() }} 69 | run: | 70 | docker stop antmedia 71 | docker rm antmedia 72 | sudo systemctl start antmedia 73 | -------------------------------------------------------------------------------- /.github/workflows/install-latest-snapshot-to-ubuntu-22-04.yml: -------------------------------------------------------------------------------- 1 | name: Install Latest Snapshot to Ubuntu 22.04 2 | on: [push] 3 | 4 | jobs: 5 | Install-Ubuntu-22-04: 6 | runs-on: ubuntu-22.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v3 10 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | 12 | - run: wget -O maven-metadata.xml https://oss.sonatype.org/service/local/repositories/snapshots/content/io/antmedia/ant-media-server/maven-metadata.xml 13 | #Get latest snapshot 14 | - run: | 15 | export LATEST_SNAPSHOT=$(grep -oP '(?<=)[^<]+' maven-metadata.xml| tail -1) 16 | echo $LATEST_SNAPSHOT 17 | wget -O ant-media-server-community.zip "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.antmedia&a=ant-media-server&v=${LATEST_SNAPSHOT}&c=community&e=zip"; 18 | - run: ./install_ant-media-server.sh -i ant-media-server-community.zip 19 | - run: sudo service antmedia status 20 | - run: sleep 30 21 | - run: cat /usr/local/antmedia/log/ant-media-server.log 22 | - run: | 23 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 24 | echo "LiveApp started log does not exist. Check the logs above" 25 | exit 1; 26 | fi; 27 | - run: cat /usr/local/antmedia/log/antmedia-error.log 28 | -------------------------------------------------------------------------------- /.github/workflows/install-latest-snapshot-to-ubuntu-24-04.yml: -------------------------------------------------------------------------------- 1 | name: Install Latest Snapshot to Ubuntu 24.04 2 | on: [push] 3 | 4 | jobs: 5 | Install-Ubuntu-24-04: 6 | runs-on: ubuntu-24.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v3 10 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | 12 | - run: wget -O maven-metadata.xml https://oss.sonatype.org/service/local/repositories/snapshots/content/io/antmedia/ant-media-server/maven-metadata.xml 13 | #Get latest snapshot 14 | - run: | 15 | export LATEST_SNAPSHOT=$(grep -oP '(?<=)[^<]+' maven-metadata.xml| tail -1) 16 | echo $LATEST_SNAPSHOT 17 | wget -O ant-media-server-community.zip "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.antmedia&a=ant-media-server&v=${LATEST_SNAPSHOT}&c=community&e=zip"; 18 | - run: ./install_ant-media-server.sh -i ant-media-server-community.zip 19 | - run: sudo service antmedia status 20 | - run: sleep 30 21 | - run: cat /usr/local/antmedia/log/ant-media-server.log 22 | - run: | 23 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 24 | echo "LiveApp started log does not exist. Check the logs above" 25 | exit 1; 26 | fi; 27 | - run: cat /usr/local/antmedia/log/antmedia-error.log 28 | -------------------------------------------------------------------------------- /.github/workflows/install-latest-to-ubuntu-22-04.yml: -------------------------------------------------------------------------------- 1 | name: Install Latest to Ubuntu 22.04 2 | on: [push] 3 | 4 | jobs: 5 | Install-Ubuntu-22-04: 6 | runs-on: ubuntu-22.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v3 10 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | #Get latest version 12 | - run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 13 | - run: ./install_ant-media-server.sh -i ant-media-server-community.zip 14 | - run: sleep 30 15 | - run: cat /usr/local/antmedia/log/ant-media-server.log 16 | - run: | 17 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 18 | echo "LiveApp started log does not exist. Check the logs above" 19 | exit 1; 20 | fi; 21 | - run: cat /usr/local/antmedia/log/antmedia-error.log 22 | Auto-Install-Community-: 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - name: Check out repository code 26 | uses: actions/checkout@v3 27 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 28 | #Get latest version 29 | - run: ./install_ant-media-server.sh 30 | - run: sleep 30 31 | - run: cat /usr/local/antmedia/log/ant-media-server.log 32 | - run: | 33 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 34 | echo "LiveApp started log does not exist. Check the logs above" 35 | exit 1; 36 | fi; 37 | - run: cat /usr/local/antmedia/log/antmedia-error.log 38 | Auto-Install-Enterprise-: 39 | runs-on: ubuntu-22.04 40 | steps: 41 | - name: Check out repository code 42 | uses: actions/checkout@v3 43 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 44 | #Get latest version 45 | - run: bash -x ./install_ant-media-server.sh -l"${{ secrets.ENTERPRISE_LICENSE }}" 46 | - run: sleep 30 47 | - run: cat /usr/local/antmedia/log/ant-media-server.log 48 | - run: | 49 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 50 | echo "LiveApp started log does not exist. Check the logs above" 51 | exit 1; 52 | fi; 53 | - run: cat /usr/local/antmedia/log/antmedia-error.log 54 | -------------------------------------------------------------------------------- /.github/workflows/install-latest-to-ubuntu-24-04.yml: -------------------------------------------------------------------------------- 1 | name: Install Latest to Ubuntu 24.04 2 | on: [push] 3 | 4 | jobs: 5 | Install-Ubuntu-24-04: 6 | runs-on: ubuntu-24.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v3 10 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 11 | #Get latest version 12 | - run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 13 | - run: ./install_ant-media-server.sh -i ant-media-server-community.zip 14 | - run: sleep 30 15 | - run: cat /usr/local/antmedia/log/ant-media-server.log 16 | - run: | 17 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 18 | echo "LiveApp started log does not exist. Check the logs above" 19 | exit 1; 20 | fi; 21 | - run: cat /usr/local/antmedia/log/antmedia-error.log 22 | Auto-Install-Community-: 23 | runs-on: ubuntu-24.04 24 | steps: 25 | - name: Check out repository code 26 | uses: actions/checkout@v3 27 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 28 | #Get latest version 29 | - run: ./install_ant-media-server.sh 30 | - run: sleep 30 31 | - run: cat /usr/local/antmedia/log/ant-media-server.log 32 | - run: | 33 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 34 | echo "LiveApp started log does not exist. Check the logs above" 35 | exit 1; 36 | fi; 37 | - run: cat /usr/local/antmedia/log/antmedia-error.log 38 | Auto-Install-Enterprise-: 39 | runs-on: ubuntu-24.04 40 | steps: 41 | - name: Check out repository code 42 | uses: actions/checkout@v3 43 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 44 | #Get latest version 45 | - run: bash -x ./install_ant-media-server.sh -l"${{ secrets.ENTERPRISE_LICENSE }}" 46 | - run: sleep 30 47 | - run: cat /usr/local/antmedia/log/ant-media-server.log 48 | - run: | 49 | if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then 50 | echo "LiveApp started log does not exist. Check the logs above" 51 | exit 1; 52 | fi; 53 | - run: cat /usr/local/antmedia/log/antmedia-error.log 54 | -------------------------------------------------------------------------------- /.github/workflows/mongodb-install-test.yml: -------------------------------------------------------------------------------- 1 | name: Test MongoDB Installation 2 | 3 | on: [push] 4 | 5 | jobs: 6 | test-mongodb: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: [ubuntu-22.04, ubuntu-24.04] 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Run MongoDB installation script 17 | run: bash ./install_mongodb.sh --auto-create 18 | 19 | - name: Verify MongoDB service 20 | run: | 21 | sudo systemctl restart mongod 22 | sudo systemctl enable mongod 23 | sleep 5 24 | systemctl is-active mongod || (echo "MongoDB failed to start" && exit 1) 25 | 26 | - name: Test MongoDB authentication 27 | run: | 28 | USERNAME=$(cat /tmp/mongo_credentials.txt | awk '{print $3}' | head -1) 29 | PASSWORD=$(cat /tmp/mongo_credentials.txt | awk '{print $3}' | tail -1) 30 | echo "Testing login with user: $USERNAME" 31 | echo "show dbs" | mongosh --username "$USERNAME" --password "$PASSWORD" --authenticationDatabase admin || (echo "Authentication failed" && exit 1) 32 | -------------------------------------------------------------------------------- /.github/workflows/rockylinux.yml: -------------------------------------------------------------------------------- 1 | name: RockyLinux 2 | on: [push] 3 | 4 | jobs: 5 | RockyLinux8: 6 | runs-on: ubuntu-24.04 7 | container: rockylinux:8 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: ./.github/actions/deploy-rockylinux-8 11 | RockyLinux9: 12 | runs-on: ubuntu-24.04 13 | container: rockylinux:9 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: ./.github/actions/deploy-rockylinux-9 -------------------------------------------------------------------------------- /.github/workflows/samples.yml: -------------------------------------------------------------------------------- 1 | name: Python Samples Script 2 | 3 | on: 4 | schedule: 5 | - cron: '0 */12 * * *' 6 | 7 | jobs: 8 | run-selenium: 9 | runs-on: ubuntu-latest 10 | 11 | env: 12 | WEBHOOK_URL: ${{ secrets.WEBHOOK }} 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v3 17 | 18 | - name: Set up Python 3 19 | uses: actions/setup-python@v3 20 | with: 21 | python-version: 3.x 22 | 23 | - name: Install dependencies 24 | run: | 25 | pip install selenium 26 | pip install requests 27 | 28 | - name: Install FFmpeg 29 | run: | 30 | sudo apt-get update 31 | sudo apt-get install -y ffmpeg 32 | 33 | - name: Install SRT 34 | run: | 35 | git clone https://github.com/Haivision/srt.git 36 | cd srt 37 | sudo apt-get install tclsh pkg-config cmake libssl-dev build-essential 38 | ./configure 39 | make 40 | sudo make install 41 | cd .. 42 | 43 | - name: Install Chrome 44 | run: | 45 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 46 | sudo dpkg -i google-chrome-stable_current_amd64.deb 47 | 48 | - name: Install ChromeDriver 49 | run: | 50 | wget https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.98/linux64/chromedriver-linux64.zip 51 | unzip chromedriver-linux64.zip 52 | cd chromedriver-linux64 53 | sudo mv chromedriver /usr/bin/chromedriver 54 | sudo chown root:root /usr/bin/chromedriver 55 | sudo chmod +x /usr/bin/chromedriver 56 | 57 | - name: Run Selenium script 58 | run: | 59 | python Selenium/antmedia-samples.py 60 | 61 | - name: Install jq 62 | run: sudo apt-get install -y jq 63 | 64 | - name: Send Slack notification on failure 65 | if: ${{ failure() || cancelled() }} 66 | run: | 67 | SLACK_PAYLOAD=$(jq -n --arg text "<@U01UMD36SQ0> GitHub Workflow failed for ${{ github.repository }}" '{text: $text, icon_emoji: ":x:"}') 68 | curl -X POST -H 'Content-type: application/json' --data "$SLACK_PAYLOAD" ${{ env.WEBHOOK_URL }} 69 | -------------------------------------------------------------------------------- /.github/workflows/uninstall-ams.yml: -------------------------------------------------------------------------------- 1 | name: Uninstall Ant Media Server 2 | on: [push] 3 | 4 | jobs: 5 | test-uninstall: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v3 10 | 11 | - name: Set up test environment 12 | run: | 13 | sudo apt-get update 14 | sudo apt-get install -y curl systemd 15 | 16 | - name: Download and install Ant Media Server 17 | run: | 18 | wget https://raw.githubusercontent.com/ant-media/Scripts/refs/heads/master/install_ant-media-server.sh 19 | curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) 20 | bash ./install_ant-media-server.sh -i ant-media-server-community.zip 21 | 22 | - name: Verify AMS Installation 23 | run: | 24 | sleep 30 25 | systemctl is-active antmedia 26 | test -d /usr/local/antmedia 27 | ps -aux |grep antmedia 28 | 29 | - name: Run uninstall script 30 | run: | 31 | wget https://raw.githubusercontent.com/ant-media/Ant-Media-Server/refs/heads/master/src/main/server/uninstall.sh 32 | sudo bash ./uninstall.sh <<< "yes" 33 | 34 | - name: Verify uninstallation 35 | run: | 36 | # Check if service file is removed 37 | test ! -f /etc/systemd/system/antmedia.service 38 | # Check if installation directory is removed 39 | test ! -d /usr/local/antmedia 40 | # Check if log directory is removed 41 | test ! -d /var/log/antmedia 42 | -------------------------------------------------------------------------------- /.github/workflows/upgrade-sh-validation.yml: -------------------------------------------------------------------------------- 1 | name: upgrade.sh Validation Test 2 | on: [push] 3 | 4 | jobs: 5 | install_and_upgrade_ant_media_server: 6 | runs-on: ubuntu-latest 7 | name: Install Previous Version of Ant Media Server 8 | steps: 9 | - name: Check out repository code 10 | uses: actions/checkout@v3 11 | - name: Install Ant Media Server 12 | run: | 13 | curl --progress-bar -o ams_community.zip -L "$(curl -s -H "Accept: application/vnd.github+json" https://api.github.com/repos/ant-media/Ant-Media-Server/releases | jq -r '.[1].assets[0].browser_download_url')" 14 | wget https://raw.githubusercontent.com/ant-media/Scripts/master/install_ant-media-server.sh 15 | sudo bash ./install_ant-media-server.sh -i ams_community.zip 16 | sleep 30 17 | PREVIOUS_VERSION=$(unzip -p /usr/local/antmedia/ant-media-server.jar | grep -a "Implementation-Version"|cut -d' ' -f2 | tr -d '\r') 18 | echo "Previous Version: $PREVIOUS_VERSION" 19 | wget https://raw.githubusercontent.com/ant-media/Ant-Media-Server/master/src/main/server/upgrade.sh 20 | DIR='/usr/local/antmedia/' sudo bash ./upgrade.sh 21 | sleep 20 22 | wget http://localhost:5080 -O index.html 23 | CURRENT_VERSION=$(unzip -p /usr/local/antmedia/ant-media-server.jar | grep -a "Implementation-Version"|cut -d' ' -f2 | tr -d '\r') 24 | (if [ "$(printf "%s\n" "$PREVIOUS_VERSION" "$CURRENT_VERSION" | sort -V | tail -n 1)" = "$PREVIOUS_VERSION" ]; 25 | then 26 | echo "It's not upgraded to the latest release.PREVIOUS_VERSION-> $PREVIOUS_VERSION and CURRENT_VERSION-> $CURRENT_VERSION "; 27 | exit 1; 28 | elif [ "$VERSION_PREVIOUS_THAN_LATEST_RELEASE" != "$CURRENT_VERSION" ]; then 29 | echo "Version upgraded to the latest release -> from PREVIOUS_VERSION-> $PREVIOUS_VERSION to CURRENT_VERSION->$CURRENT_VERSION "; 30 | fi) 31 | 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | ehthumbs.db 9 | Thumbs.db 10 | /.project 11 | -------------------------------------------------------------------------------- /24x7-testing/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /24x7-testing/24x7-test1.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import requests 4 | import paramiko 5 | import json 6 | 7 | webhook_url = os.environ['WEBHOOK_URL'] 8 | icon_emoji = ":ghost:" 9 | 10 | def send_slack_message(webhook_url, message, icon_emoji=":ghost:"): 11 | payload = { 12 | "text": message, 13 | "icon_emoji": icon_emoji 14 | } 15 | response = requests.post(webhook_url, data={"payload": json.dumps(payload)}) 16 | 17 | if response.status_code != 200: 18 | print("Error sending Slack message: ", response.text) 19 | else: 20 | print("Slack message sent successfully!") 21 | 22 | def check_stream_status(api_url): 23 | try: 24 | # Make the GET request to the API 25 | response = requests.get(api_url) 26 | response.raise_for_status() # Raise an HTTPError for bad status codes 27 | 28 | response_data = response.json() 29 | 30 | # Extract the required fields 31 | status = response_data.get("status") 32 | webRTCViewerCount = response_data.get("webRTCViewerCount") 33 | 34 | # Check if the status is "broadcasting" and webRTCViewerCount is 1 35 | if status == "broadcasting" and webRTCViewerCount == 1: 36 | print("Stream is broadcasting with 1 WebRTC viewer.") 37 | else: 38 | message = "Stream is not broadcasting or there is no viewer" 39 | send_slack_message(webhook_url, message, icon_emoji) 40 | return False 41 | 42 | except requests.exceptions.RequestException as e: 43 | print(f"Error making the API call: {e}") 44 | message = "Error making the API call" 45 | send_slack_message(webhook_url, message, icon_emoji) 46 | return False 47 | 48 | except requests.exceptions.HTTPError as e: 49 | print(f"HTTP error: {e}") 50 | message = "HTTP error when making the API call" 51 | send_slack_message(webhook_url, message, icon_emoji) 52 | return False 53 | 54 | except ValueError as e: 55 | print(f"Error: {e}") 56 | return False 57 | 58 | except Exception as e: 59 | print(f"Unexpected error: {e}") 60 | return False 61 | 62 | return True 63 | 64 | def check_server_for_errors(server_ip, username, password): 65 | try: 66 | # SSH into the server 67 | client = paramiko.SSHClient() 68 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 69 | client.connect(server_ip, username=username, password=password) 70 | 71 | # Check for error files 72 | file_extensions = [".log", ".hprof"] 73 | error_files = [] 74 | 75 | for ext in file_extensions: 76 | stdin, stdout, stderr = client.exec_command(f"ls /usr/local/antmedia/*{ext}") 77 | error_files.extend(stdout.readlines()) 78 | 79 | if error_files: 80 | print("Error files found:") 81 | for file in error_files: 82 | print(file.strip()) 83 | message = "The crash log or dump file is found on the server in 24x7 staging enviornment. Please check the logs" 84 | send_slack_message(webhook_url, message, icon_emoji) 85 | else: 86 | print("No error files found") 87 | 88 | except paramiko.AuthenticationException as e: 89 | print(f"Authentication failed: {e}") 90 | except paramiko.SSHException as e: 91 | print(f"SSH error: {e}") 92 | except Exception as e: 93 | print(f"Unexpected error: {e}") 94 | finally: 95 | client.close() 96 | 97 | if __name__ == "__main__": 98 | api_url = "https://test.antmedia.io:5443/24x7test/rest/v2/broadcasts/24x7test" 99 | if check_stream_status(api_url): 100 | # Replace the following with server details 101 | server_ip = os.environ['SERVER_IP'] 102 | username = os.environ['USERNAME'] 103 | password = os.environ['PASSWORD'] 104 | 105 | check_server_for_errors(server_ip, username, password) 106 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | docker/Dockerfile_Service -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | Auxiliary Scripts 3 | 4 | If you have any issue, please open on 5 | https://github.com/ant-media/Ant-Media-Server/issues 6 | -------------------------------------------------------------------------------- /ams_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Usage 3 | #First parameter is the version name either release or snapshot works 4 | #if it is release version, script create and checkout a branch, update version, commit, tag and push the script 5 | # ./ams_release.sh 1.6.1 6 | #if it is release version with branch parameter, script create & checkout a branch and push the 7 | #./ams_release.sh 1.6.1 branch 8 | #if it is a snapshot version, it updates the version, commits and pushes . After that it should be merged with master 9 | #./ams_release.sh 1.6.2-SNAPSHOT 10 | 11 | #Future work: Deploying to maven central takes about 2-3 hours so that it blocks Ant-Media-Server to pass the test. 12 | #another solution we may add sonatype as release repo 13 | 14 | if [ -z "$1" ]; then 15 | echo "Please give the version as parameter" 16 | echo "Sample usage:" 17 | echo "$0 1.6.1 -> create & checkout the release branch, update version, commit, tag and push to the origin" 18 | echo "$0 1.6.1 branch -> create & checkout the release branch, don't update version, push to the origin " 19 | echo "$0 1.6.1-SNAPSHOT -> update the version, commit and push to the origin" 20 | exit 1 21 | fi 22 | 23 | 24 | check() { 25 | OUT=$1 26 | if [ $OUT -ne 0 ]; then 27 | echo "There is a problem in releasing. Please check the log above" 28 | exit $OUT 29 | fi 30 | } 31 | 32 | #Creates a new branch, update version 33 | #commit, tag and push 34 | #### Update below script if the operation is done previously and re-executed again 35 | update_version_and_push() 36 | { 37 | NEW_VERSION=$1 38 | BRANCH_NAME=release/$NEW_VERSION 39 | TAG_NAME=ams-v$NEW_VERSION 40 | 41 | ALLOW_SNAPSHOT="" 42 | #create and checkout branch 43 | if [[ ! $NEW_VERSION =~ .*SNAPSHOT$ ]]; #if it is not a snapshot version 44 | then 45 | echo "Checking out $BRANCH_NAME" 46 | if [ `git branch --list $BRANCH_NAME | wc -l` == "0" ] 47 | then 48 | echo "$BRANCH_NAME branch is being created." 49 | git branch $BRANCH_NAME 50 | fi 51 | git checkout $BRANCH_NAME 52 | else 53 | #if it is a snasphot version allow latest snapshot 54 | ALLOW_SNAPSHOT=-DallowSnapshots=true 55 | fi 56 | 57 | check $? 58 | 59 | 60 | CURRENT_DIR=`pwd` 61 | 62 | # Check the current directory by default 63 | declare -a directoriesToCheck=( 64 | "." 65 | ) 66 | 67 | #if it's plugins directory, enter each subdirectory and update the pom file 68 | if [[ $CURRENT_DIR =~ .*Plugins$ ]]; then 69 | directoriesToCheck=(*/) 70 | fi 71 | 72 | COMMIT_POM=false 73 | 74 | # if it's Plugins directory, it walks through all subdirectories and update the parent mvn 75 | # if it's not Plugins directory, it just go to current directory(.) 76 | for subdir in "${directoriesToCheck[@]}"; 77 | do 78 | cd $CURRENT_DIR/$subdir 79 | #run maven comments if pom.xml exists 80 | if [[ -f "pom.xml" ]]; then 81 | 82 | if [[ ! "$2" = "branch" && ! "$3" = "branch" ]] # if it's not branch, update the version 83 | then 84 | if [ "$2" = "self" ] 85 | then 86 | #project's own version is updated 87 | mvn versions:set -DnewVersion=$NEW_VERSION 88 | else 89 | #project's parent is updated 90 | mvn versions:update-parent -DparentVersion=$NEW_VERSION $ALLOW_SNAPSHOT 91 | fi 92 | check $? 93 | 94 | #add change pom.xml 95 | git add pom.xml 96 | check $? 97 | 98 | COMMIT_POM=true 99 | fi 100 | fi 101 | done 102 | 103 | if [ "$COMMIT_POM" = true ] ; then 104 | #commit pom.xml 105 | git commit -m "Update version to $NEW_VERSION" 106 | check $? 107 | fi 108 | 109 | #push branch to remote 110 | if [[ ! $NEW_VERSION =~ .*SNAPSHOT$ ]]; 111 | then 112 | # if it is not snapshot push to the origin with branch name 113 | git push -u origin $BRANCH_NAME 114 | else 115 | # if it is snapshot, just push HEAD to the origin 116 | git push origin HEAD 117 | fi 118 | check $? 119 | 120 | if [[ ! "$2" = "branch" && ! "$3" = "branch" ]] # if it's not branch, tag the version 121 | then 122 | if [[ ! $NEW_VERSION =~ .*SNAPSHOT$ ]]; 123 | then 124 | #tag branch 125 | git tag $TAG_NAME 126 | check $? 127 | #push tags 128 | git push origin --tags 129 | check $? 130 | fi 131 | fi 132 | } 133 | 134 | CURRENT_PATH=`pwd` 135 | declare -a arr=( 136 | "Ant-Media-Server" 137 | "Ant-Media-Enterprise" 138 | "Ant-Media-Management-Console" 139 | "StreamApp" 140 | "webrtc-test" 141 | "testcluster" 142 | "Plugins" 143 | ) 144 | 145 | VERSION=$1 146 | BRANCH_PARAMETER=$2 147 | 148 | PARENT_PATH=$CURRENT_PATH/Ant-Media-Server-Parent 149 | cd $PARENT_PATH 150 | 151 | update_version_and_push $VERSION self $BRANCH_PARAMETER 152 | mvn install -Dgpg.skip=true 153 | 154 | ## loop through the array 155 | for i in "${arr[@]}" 156 | do 157 | echo "Entering $i" 158 | cd $CURRENT_PATH/$i 159 | update_version_and_push $VERSION $BRANCH_PARAMETER 160 | done 161 | 162 | if [[ $VERSION =~ .*SNAPSHOT$ ]]; 163 | then 164 | echo "Make Pull Request to master branch for all projects below" 165 | else 166 | echo "Check that all projects below have passed CI/CD" 167 | fi 168 | 169 | echo "Ant-Media-Server-Parent" 170 | for i in "${arr[@]}" 171 | do 172 | echo "$i" 173 | done 174 | -------------------------------------------------------------------------------- /aws/ant_media_server_aws_cluster_update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import boto3, time, argparse 4 | 5 | """ 6 | ant_media_server_aws_cluster_update.py 7 | 8 | Description: This script terminates the existing instances (except MongoDB) and recreates them with a new image. 9 | 10 | Usage: 11 | python ant_media_server_aws_cluster_update.py --origin --edge 12 | 13 | Options: 14 | -h, --help Show this help message and exit 15 | --origin Specify the name of the origin autoscaling group 16 | --edge Specify the name of the edge autoscaling group 17 | 18 | Examples: 19 | python ant_media_server_aws_cluster_update.py --origin origin-auto-scaling-group --edge edge-auto-scaling-group 20 | """ 21 | 22 | if __name__ == "__main__": 23 | # Parse command line arguments 24 | parser = argparse.ArgumentParser(description='Your script description') 25 | parser.add_argument('--origin', type=str, help='Specify the name of the origin autoscaling group') 26 | parser.add_argument('--edge', type=str, help='Specify the name of the edge autoscaling group') 27 | args = parser.parse_args() 28 | 29 | # Assign the provided autoscaling group names to the respective variables 30 | origin_group_name = args.origin 31 | edge_group_name = args.edge 32 | 33 | 34 | ec2_client = boto3.client('ec2') 35 | autoscaling_client = boto3.client('autoscaling') 36 | 37 | # Ant Media Server Enterprise Edition details 38 | Name="AntMedia-AWS-Marketplace-EE-*" 39 | Arch="x86_64" 40 | Owner="679593333241" 41 | 42 | # Get the latest AMI of Ant Media Server 43 | def image_id(): 44 | 45 | image_response = boto3.client('ec2').describe_images( 46 | Owners=[Owner], 47 | Filters=[ 48 | {'Name': 'name', 'Values': [Name]}, 49 | {'Name': 'architecture', 'Values': [Arch]}, 50 | {'Name': 'root-device-type', 'Values': ['ebs']}, 51 | ], 52 | ) 53 | 54 | ami = sorted(image_response['Images'], 55 | key=lambda x: x['CreationDate'], 56 | reverse=True) 57 | return (ami[0]['ImageId']) 58 | 59 | class AutoscaleSettings: 60 | def __init__(self, autoscaling_client, group_name): 61 | self.autoscaling_client = autoscaling_client 62 | self.group_name = group_name 63 | self.desired_capacity = None 64 | self.min_size = None 65 | self.max_size = None 66 | 67 | def retrieve_settings(self): 68 | response = self.autoscaling_client.describe_auto_scaling_groups(AutoScalingGroupNames=[self.group_name]) 69 | auto_scaling_group = response['AutoScalingGroups'][0] 70 | 71 | self.desired_capacity = auto_scaling_group['DesiredCapacity'] 72 | self.min_size = auto_scaling_group['MinSize'] 73 | self.max_size = auto_scaling_group['MaxSize'] 74 | self.launch_config_name = auto_scaling_group['LaunchConfigurationName'] 75 | response_1 = autoscaling_client.describe_launch_configurations( 76 | LaunchConfigurationNames=[self.launch_config_name] 77 | ) 78 | self.launch_configuration = response_1['LaunchConfigurations'][0] 79 | def update_autoscale(self): 80 | print ("#########", self.group_name, "#########") 81 | print("The instances are terminating.") 82 | terminate_instances = autoscaling_client.update_auto_scaling_group( 83 | AutoScalingGroupName=self.group_name, 84 | MinSize=0, 85 | DesiredCapacity=0, 86 | MaxSize=0, 87 | ) 88 | time.sleep(10) 89 | print ("Creating new Launch Templates") 90 | create_new_launch_template = autoscaling_client.create_launch_configuration( 91 | LaunchConfigurationName=self.launch_config_name + '-updated', 92 | ImageId=str(image_id()), 93 | InstanceType=self.launch_configuration['InstanceType'], 94 | ) 95 | time.sleep(5) 96 | print ("Updating the Auto-Scaling Groups") 97 | update_autoscale = autoscaling_client.update_auto_scaling_group( 98 | AutoScalingGroupName=self.group_name, 99 | LaunchConfigurationName=self.launch_config_name + '-updated' 100 | 101 | ) 102 | time.sleep(10) 103 | print ("New instances are creating with the latest version of Ant Media Server EE") 104 | update_capacity = autoscaling_client.update_auto_scaling_group( 105 | AutoScalingGroupName=self.group_name, 106 | MinSize=self.min_size, 107 | DesiredCapacity=self.desired_capacity, 108 | MaxSize=self.max_size, 109 | ) 110 | print("##################") 111 | 112 | 113 | # Create an instance of the AutoscaleSettings class 114 | origin_settings = AutoscaleSettings(autoscaling_client, origin_group_name) 115 | edge_settings = AutoscaleSettings(autoscaling_client, edge_group_name) 116 | 117 | # Get settings 118 | origin_settings.retrieve_settings() 119 | edge_settings.retrieve_settings() 120 | 121 | # Update Auto-Scaling 122 | origin_settings.update_autoscale() 123 | edge_settings.update_autoscale() 124 | -------------------------------------------------------------------------------- /cloudformation/cf-snippets/edge-launch-config.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::AutoScaling::LaunchConfiguration' 2 | DependsOn: 3 | - ApplicationLoadBalancer 4 | Metadata: 5 | Comment: Install a simple application 6 | 'AWS::CloudFormation::Init': 7 | configSets: 8 | setup: 9 | - "configure_cfn" 10 | configure_cfn: 11 | files: 12 | /etc/cfn/cfn-hup.conf: 13 | content: 14 | Fn::Sub: | 15 | [main] 16 | stack=${AWS::StackId} 17 | region=${AWS::Region} 18 | verbose=true 19 | interval=5 20 | mode: "000400" 21 | owner: root 22 | group: root 23 | /etc/cfn/hooks.d/cfn-auto-reloader.conf: 24 | content: 25 | Fn::Sub: | 26 | [cfn-auto-reloader-hook] 27 | triggers=post.update 28 | path=Resources.LaunchConfigEdge.Metadata.AWS::CloudFormation::Init 29 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfigEdge --configsets setup --region ${AWS::Region} 30 | mode: "000400" 31 | owner: root 32 | group: root 33 | /lib/systemd/system/cfn-hup.service: 34 | content: 35 | Fn::Sub: | 36 | [Unit] 37 | Description=cfn-hup daemon 38 | 39 | [Service] 40 | Type=simple 41 | ExecStart=/opt/aws/bin/cfn-hup 42 | Restart=always 43 | 44 | [Install] 45 | WantedBy=multi-user.target 46 | mode: "000400" 47 | owner: root 48 | group: root 49 | 50 | Properties: 51 | KeyName: 52 | Ref: KeyName 53 | ImageId: 54 | Ref: AntMediaAmi 55 | SecurityGroups: 56 | - Ref: InstanceSecurityGroup 57 | InstanceType: 58 | Ref: EdgeInstanceType 59 | BlockDeviceMappings: 60 | - DeviceName: /dev/sda1 61 | Ebs: 62 | VolumeSize: 63 | Ref: DiskSize 64 | VolumeType: gp2 65 | DeleteOnTermination: true 66 | UserData: 67 | Fn::Base64: 68 | Fn::Sub: | 69 | #!/bin/bash 70 | if [ ${Monitor} == "true" ]; then 71 | sudo sed -i "s/server.kafka_brokers=.*/server.kafka_brokers=${MonitorInstance.PrivateIp}:9092/g" /usr/local/antmedia/conf/red5.properties 72 | fi 73 | bash /usr/local/antmedia/change_server_mode.sh cluster ${MongoDBInstance.PrivateIp} 74 | apt-get update 75 | apt-get install -y python3-pip 76 | apt-get install -y python3-setuptools 77 | mkdir -p /opt/aws/bin 78 | wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz 79 | python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz 80 | /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfigEdge --configsets setup --region ${AWS::Region} 81 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} -------------------------------------------------------------------------------- /cloudformation/cf-snippets/edge.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::AutoScaling::AutoScalingGroup' 2 | DependsOn: 3 | - LaunchConfigEdge 4 | Properties: 5 | VPCZoneIdentifier: 6 | Ref: Subnets 7 | LaunchConfigurationName: 8 | Ref: LaunchConfigEdge 9 | MinSize: 10 | Ref: AntMediaEdgeCapacity 11 | MaxSize: 12 | Ref: AntMediaEdgeCapacityMax 13 | DesiredCapacity: 14 | Ref: AntMediaEdgeCapacity 15 | TargetGroupARNs: 16 | - Ref: ALBTargetGroupEdge 17 | Tags: 18 | - Key: Name 19 | Value: Antmedia-Edge 20 | PropagateAtLaunch: 'true' 21 | CreationPolicy: 22 | ResourceSignal: 23 | Timeout: PT15M 24 | Count: 25 | Ref: AntMediaEdgeCapacity 26 | UpdatePolicy: 27 | AutoScalingRollingUpdate: 28 | MinInstancesInService: '1' 29 | MaxBatchSize: '1' 30 | PauseTime: PT15M 31 | WaitOnResourceSignals: 'true' 32 | NotificationConfiguration: 33 | TopicARN: 34 | Ref: NotificationTopic 35 | NotificationTypes: 36 | - 'autoscaling:EC2_INSTANCE_LAUNCH' 37 | - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' 38 | - 'autoscaling:EC2_INSTANCE_TERMINATE' 39 | - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' -------------------------------------------------------------------------------- /cloudformation/cf-snippets/mongodb.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::EC2::Instance' 2 | DependsOn: MongoDBSecurityGroup 3 | Properties: 4 | KeyName: 5 | Ref: KeyName 6 | ImageId: 7 | Ref: UbuntuAmi 8 | InstanceType: 9 | Ref: MongoDBInstanceType 10 | SubnetId: 11 | Fn::Select: [ 0, Ref: Subnets ] 12 | SecurityGroupIds: 13 | - Fn::GetAtt: [ MongoDBSecurityGroup, GroupId ] 14 | Tags: 15 | - Key: Name 16 | Value: Antmedia-MongoDB 17 | UserData: 18 | Fn::Base64: 19 | Fn::Sub: | 20 | #!/bin/bash -xe 21 | wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - 22 | echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list 23 | sudo apt-get update 24 | sudo apt-get install -y mongodb-org python3-pip python3-setuptools 25 | sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf 26 | systemctl enable mongod 27 | systemctl restart mongod 28 | wget -P /tmp/ https://raw.githubusercontent.com/ant-media/Scripts/master/cloudformation/cloudformation_set_username_password.sh && chmod +x /tmp/cloudformation_set_username_password.sh 29 | echo "/tmp/cloudformation_set_username_password.sh ${DashboardUsername} ${DashboardPassword}"| at now + 2 minutes 30 | 31 | 32 | -------------------------------------------------------------------------------- /cloudformation/cf-snippets/monitor.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::EC2::Instance' 2 | Properties: 3 | KeyName: antmedia-test 4 | ImageId: 5 | Ref: UbuntuAmi 6 | InstanceType: 7 | Ref: MonitorInstanceType 8 | SubnetId: 9 | Fn::Select: [ 0, Ref: Subnets ] 10 | SecurityGroupIds: 11 | - Fn::GetAtt: [ MonitorSecurityGroup, GroupId ] 12 | Tags: 13 | - Key: Name 14 | Value: Antmedia-Monitor 15 | UserData: 16 | Fn::Base64: 17 | Fn::Sub: | 18 | #!/bin/bash -xe 19 | wget https://raw.githubusercontent.com/ant-media/Scripts/master/install-monitoring-tools.sh 20 | bash install-monitoring-tools.sh -y 21 | -------------------------------------------------------------------------------- /cloudformation/cf-snippets/origin-launch-config.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::AutoScaling::LaunchConfiguration' 2 | DependsOn: 3 | - ApplicationLoadBalancer 4 | Metadata: 5 | Comment: Install a simple application 6 | 'AWS::CloudFormation::Init': 7 | configSets: 8 | setup: 9 | - "configure_cfn" 10 | configure_cfn: 11 | files: 12 | /etc/cfn/cfn-hup.conf: 13 | content: 14 | Fn::Sub: | 15 | [main] 16 | stack=${AWS::StackId} 17 | region=${AWS::Region} 18 | verbose=true 19 | interval=5 20 | mode: "000400" 21 | owner: root 22 | group: root 23 | /etc/cfn/hooks.d/cfn-auto-reloader.conf: 24 | content: 25 | Fn::Sub: | 26 | [cfn-auto-reloader-hook] 27 | triggers=post.update 28 | path=Resources.LaunchConfigOrigin.Metadata.AWS::CloudFormation::Init 29 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfigOrigin --configsets setup --region ${AWS::Region} 30 | mode: "000400" 31 | owner: root 32 | group: root 33 | /lib/systemd/system/cfn-hup.service: 34 | content: 35 | Fn::Sub: | 36 | [Unit] 37 | Description=cfn-hup daemon 38 | 39 | [Service] 40 | Type=simple 41 | ExecStart=/opt/aws/bin/cfn-hup 42 | Restart=always 43 | 44 | [Install] 45 | WantedBy=multi-user.target 46 | mode: "000400" 47 | owner: root 48 | group: root 49 | 50 | Properties: 51 | KeyName: 52 | Ref: KeyName 53 | ImageId: 54 | Ref: AntMediaAmi 55 | SecurityGroups: 56 | - Ref: InstanceSecurityGroup 57 | InstanceType: 58 | Ref: OriginInstanceType 59 | BlockDeviceMappings: 60 | - DeviceName: /dev/sda1 61 | Ebs: 62 | VolumeSize: 63 | Ref: DiskSize 64 | VolumeType: gp2 65 | DeleteOnTermination: true 66 | UserData: 67 | Fn::Base64: 68 | Fn::Sub: | 69 | #!/bin/bash 70 | if [ ${Monitor} == "true" ]; then 71 | sudo sed -i "s/server.kafka_brokers=.*/server.kafka_brokers=${MonitorInstance.PrivateIp}:9092/g" /usr/local/antmedia/conf/red5.properties 72 | fi 73 | bash /usr/local/antmedia/change_server_mode.sh cluster ${MongoDBInstance.PrivateIp} 74 | apt-get update -y 75 | apt-get install -y python3-pip 76 | apt-get install -y python3-setuptools 77 | mkdir -p /opt/aws/bin 78 | wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz 79 | python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz 80 | /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfigOrigin --configsets setup --region ${AWS::Region} 81 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} -------------------------------------------------------------------------------- /cloudformation/cf-snippets/origin.yaml: -------------------------------------------------------------------------------- 1 | Type: 'AWS::AutoScaling::AutoScalingGroup' 2 | DependsOn: 3 | - LaunchConfigOrigin 4 | Properties: 5 | VPCZoneIdentifier: 6 | Ref: Subnets 7 | LaunchConfigurationName: 8 | Ref: LaunchConfigOrigin 9 | MinSize: 10 | Ref: AntMediaOriginCapacity 11 | MaxSize: 12 | Ref: AntMediaOriginCapacityMax 13 | DesiredCapacity: 14 | Ref: AntMediaOriginCapacity 15 | TargetGroupARNs: 16 | - Ref: ALBTargetGroupOrigin 17 | LoadBalancerNames: 18 | - Fn::If: [CreateRTMPResources, Ref: RTMPLoadBalancer, "AWS::NoValue"] 19 | Tags: 20 | - Key: Name 21 | Value: Antmedia-Origin 22 | PropagateAtLaunch: 'true' 23 | CreationPolicy: 24 | ResourceSignal: 25 | Timeout: PT15M 26 | Count: 27 | Ref: AntMediaOriginCapacity 28 | UpdatePolicy: 29 | AutoScalingRollingUpdate: 30 | MinInstancesInService: '1' 31 | MaxBatchSize: '1' 32 | PauseTime: PT15M 33 | WaitOnResourceSignals: 'true' 34 | NotificationConfiguration: 35 | TopicARN: 36 | Ref: NotificationTopic 37 | NotificationTypes: 38 | - 'autoscaling:EC2_INSTANCE_LAUNCH' 39 | - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR' 40 | - 'autoscaling:EC2_INSTANCE_TERMINATE' 41 | - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR' -------------------------------------------------------------------------------- /cloudformation/cf-snippets/output.yaml: -------------------------------------------------------------------------------- 1 | Username: 2 | Description: Dashboard Username 3 | Value: 4 | Ref: DashboardUsername 5 | 6 | Password: 7 | Description: Dashboard Password 8 | Value: 9 | Ref: DashboardPassword 10 | 11 | OriginHTTPS: 12 | Description: HTTPS URL of the Ant Media Origin Servers 13 | Value: 14 | Fn::Join: 15 | - '' 16 | - - 'https://' 17 | - Fn::GetAtt: 18 | - ApplicationLoadBalancer 19 | - DNSName 20 | 21 | EdgeHTTPS: 22 | Description: HTTPS URL of the Ant Media Edge Servers 23 | Value: 24 | Fn::Join: 25 | - '' 26 | - - 'https://' 27 | - Fn::GetAtt: 28 | - ApplicationLoadBalancer 29 | - DNSName 30 | - ':5443' 31 | 32 | OriginHTTP: 33 | Description: HTTP URL of the Ant Media Origin Servers 34 | Value: 35 | Fn::Join: 36 | - '' 37 | - - 'http://' 38 | - Fn::GetAtt: 39 | - ApplicationLoadBalancer 40 | - DNSName 41 | 42 | EdgeHTTP: 43 | Description: HTTP URL of the Ant Media Edge Servers 44 | Value: 45 | Fn::Join: 46 | - '' 47 | - - 'http://' 48 | - Fn::GetAtt: 49 | - ApplicationLoadBalancer 50 | - DNSName 51 | - ':5080' 52 | 53 | RTMP: 54 | Condition: CreateRTMPResources 55 | Description: RTMP URL of the Ant Media Server 56 | Value: 57 | Fn::Join: 58 | - '' 59 | - - 'rtmp://' 60 | - Fn::GetAtt: 61 | - RTMPLoadBalancer 62 | - DNSName 63 | MonitorURL: 64 | Condition: CreateMonitor 65 | Description: "Grafana Default Username and Password: admin/admin" 66 | Value: 67 | Fn::Join: 68 | - '' 69 | - - 'http://' 70 | - Fn::GetAtt: 71 | - MonitorInstance 72 | - PublicIp 73 | - ':3000' 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /cloudformation/cloudformation_set_username_password.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script sets username and password in Cloudformation template 3 | 4 | USERNAME="$1" 5 | PASSWORD="$2" 6 | 7 | while [ `mongo --eval 'db.User.find()' serverdb --host 127.0.0.1 | grep "_id"|wc -l` == "0" ]; do 8 | sleep 5 9 | done 10 | 11 | for (( i=0; i<`mongo --eval 'db.User.find()' serverdb --host 127.0.0.1 | grep "_id"|wc -l`; ++i)); do 12 | mongo --eval 'db.User.deleteOne({ "email": "JamesBond" })' serverdb --host 127.0.0.1 13 | done 14 | 15 | mongo --eval 'db.User.insert ( {"email":"'$USERNAME'","password":"'`echo -n $PASSWORD | md5sum| cut -d' ' -f1`'","userType":"ADMIN"} )' serverdb --host 127.0.0.1 16 | -------------------------------------------------------------------------------- /cloudformation/graylog.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | Ant Media Server AutoScaling CloudFormation Templates. 4 | If you have any questions, please just drop a line to contact (at) antmedia.io 5 | Parameters: 6 | VpcId: 7 | Type: 'AWS::EC2::VPC::Id' 8 | Description: 'VpcId of your existing Virtual Private Cloud (VPC). The VpcId must be the same as the subnets you choose' 9 | ConstraintDescription: 'must be the VPC Id of an existing Virtual Private Cloud. The VpcId must be the same as the subnets you choose.' 10 | Subnets: 11 | Type: 'List' 12 | Description: 'You must choose at least 2 subnets from the same VPC network.' 13 | ConstraintDescription: >- 14 | must be a list of at least two existing subnets associated with at least 15 | two different availability zones. They should be residing in the selected 16 | Virtual Private Cloud. 17 | InstanceType: 18 | Description: Ant Media MongoDB EC2 instance type 19 | Type: String 20 | Default: c5.xlarge 21 | AllowedValues: 22 | - t2.large 23 | - t2.xlarge 24 | - t2.2xlarge 25 | - m3.large 26 | - m3.xlarge 27 | - m3.2xlarge 28 | - m4.large 29 | - m4.xlarge 30 | - m4.2xlarge 31 | - m4.4xlarge 32 | - m4.10xlarge 33 | - m4.16xlarge 34 | - m5.large 35 | - m5.xlarge 36 | - m5.2xlarge 37 | - m5.4xlarge 38 | - m5.12xlarge 39 | - m5.24xlarge 40 | - c3.large 41 | - c3.xlarge 42 | - c3.2xlarge 43 | - c3.4xlarge 44 | - c3.8xlarge 45 | - c4.large 46 | - c4.xlarge 47 | - c4.2xlarge 48 | - c4.4xlarge 49 | - c4.8xlarge 50 | - c5.large 51 | - c5.xlarge 52 | - c5.2xlarge 53 | - c5.4xlarge 54 | - c5.9xlarge 55 | - c5.12xlarge 56 | - c5.18xlarge 57 | - c5.24xlarge 58 | - c5d.large 59 | - c5d.xlarge 60 | - c5d.2xlarge 61 | - c5d.4xlarge 62 | - c5d.9xlarge 63 | - c5d.18xlarge 64 | - c5n.large 65 | - c5n.xlarge 66 | - c5n.2xlarge 67 | - c5n.4xlarge 68 | - c5n.9xlarge 69 | - c5n.18xlarge 70 | - r3.large 71 | - r3.xlarge 72 | - r3.2xlarge 73 | - r3.4xlarge 74 | - r3.8xlarge 75 | KeyName: 76 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). 77 | Type: 'AWS::EC2::KeyPair::KeyName' 78 | MinLength: '1' 79 | MaxLength: '255' 80 | AllowedPattern: '[\x20-\x7E]*' 81 | ConstraintDescription: can contain only ASCII characters. 82 | DashboardPassword: 83 | Description: 'Web Panel Password' 84 | Type: String 85 | Default: 'antmedia' 86 | 87 | Resources: 88 | DescribeImagesRole: 89 | Type: AWS::IAM::Role 90 | Properties: 91 | AssumeRolePolicyDocument: 92 | Version: '2012-10-17' 93 | Statement: 94 | - Action: sts:AssumeRole 95 | Effect: Allow 96 | Principal: 97 | Service: lambda.amazonaws.com 98 | ManagedPolicyArns: 99 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 100 | Policies: 101 | - PolicyName: DescribeImages 102 | PolicyDocument: 103 | Version: '2012-10-17' 104 | Statement: 105 | - Action: ec2:DescribeImages 106 | Effect: Allow 107 | Resource: "*" 108 | UbuntuGetLatestAMI: 109 | Type: AWS::Lambda::Function 110 | Properties: 111 | Runtime: python3.8 112 | Handler: index.handler 113 | Role: !Sub ${DescribeImagesRole.Arn} 114 | Timeout: 60 115 | Code: 116 | ZipFile: | 117 | import boto3 118 | import cfnresponse 119 | import json 120 | import traceback 121 | 122 | def handler(event, context): 123 | try: 124 | response = boto3.client('ec2').describe_images( 125 | Owners=[event['ResourceProperties']['Owner']], 126 | Filters=[ 127 | {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, 128 | {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, 129 | {'Name': 'root-device-type', 'Values': ['ebs']}, 130 | ], 131 | ) 132 | 133 | amis = sorted(response['Images'], 134 | key=lambda x: x['CreationDate'], 135 | reverse=True) 136 | id = amis[0]['ImageId'] 137 | 138 | cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) 139 | except: 140 | traceback.print_last() 141 | cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") 142 | 143 | UbuntuAmi: 144 | Type: Custom::FindAMI 145 | Properties: 146 | ServiceToken: !Sub ${UbuntuGetLatestAMI.Arn} 147 | Owner: "099720109477" 148 | Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" 149 | Architecture: "x86_64" 150 | 151 | EC2SecurityGroup: 152 | Type: 'AWS::EC2::SecurityGroup' 153 | Properties: 154 | VpcId: !Ref VpcId 155 | GroupDescription: Graylog SecurityGroup 156 | SecurityGroupIngress: 157 | - CidrIp: 0.0.0.0/0 158 | IpProtocol: tcp 159 | FromPort: 22 160 | ToPort: 22 161 | Description: Allow 22. Port for SSH 162 | - CidrIp: 0.0.0.0/0 163 | IpProtocol: tcp 164 | FromPort: 9000 165 | ToPort: 9000 166 | Description: Allow 9000. Port for Graylog Web Interface 167 | - CidrIp: 0.0.0.0/0 168 | IpProtocol: tcp 169 | FromPort: 5144 170 | ToPort: 5144 171 | Description: Allow 5144. Port for Graylog 172 | 173 | Instance: 174 | Type: 'AWS::EC2::Instance' 175 | DependsOn: 176 | - UbuntuAmi 177 | - DescribeImagesRole 178 | Properties: 179 | KeyName: !Ref KeyName 180 | ImageId: !Ref UbuntuAmi 181 | InstanceType: !Ref InstanceType 182 | SubnetId: !Select [ 0, !Ref Subnets ] 183 | SecurityGroupIds: 184 | - !GetAtt "EC2SecurityGroup.GroupId" 185 | Tags: 186 | - Key: Name 187 | Value: Graylog 188 | UserData: 189 | Fn::Base64: 190 | !Sub | 191 | #!/bin/bash -xe 192 | wget -O /tmp/install_graylog.sh https://raw.githubusercontent.com/ant-media/Scripts/master/install_graylog.sh 193 | sed -i "s/antmedia_password/${DashboardPassword}/g" /tmp/install_graylog.sh 194 | sudo bash /tmp/install_graylog.sh 195 | -------------------------------------------------------------------------------- /cloudformation/kafka_2.13-2.8.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant-media/Scripts/3456b0ababfd935046b6f185b4ba958f417714d3/cloudformation/kafka_2.13-2.8.1.tgz -------------------------------------------------------------------------------- /cloudformation/turnserver.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | STUN/TURN Server Installation 4 | Parameters: 5 | Subnets: 6 | Type: 'List' 7 | Description: 'You must choose at least 2 subnets from the same VPC network.' 8 | ConstraintDescription: >- 9 | must be a list of at least two existing subnets associated with at least 10 | two different availability zones. They should be residing in the selected 11 | Virtual Private Cloud. 12 | VpcId: 13 | Type: 'AWS::EC2::VPC::Id' 14 | Description: 'VpcId of your existing Virtual Private Cloud (VPC). The VpcId must be the same as the subnets you choose' 15 | ConstraintDescription: 'must be the VPC Id of an existing Virtual Private Cloud. The VpcId must be the same as the subnets you choose.' 16 | TurnServerInstanceType: 17 | Description: STUN/TURN Server Edge EC2 instance type 18 | Type: String 19 | Default: t2.micro 20 | AllowedValues: 21 | - t1.micro 22 | - t2.nano 23 | - t2.micro 24 | - t2.small 25 | - t2.medium 26 | - t2.large 27 | - m1.small 28 | - m1.medium 29 | - m1.large 30 | - m1.xlarge 31 | - m2.xlarge 32 | - m2.2xlarge 33 | - m2.4xlarge 34 | - m3.medium 35 | - m3.large 36 | - m3.xlarge 37 | - m3.2xlarge 38 | - m4.large 39 | - m4.xlarge 40 | - m4.2xlarge 41 | - m4.4xlarge 42 | - m4.10xlarge 43 | - c1.medium 44 | - c1.xlarge 45 | - c3.large 46 | - c3.xlarge 47 | - c3.2xlarge 48 | - c3.4xlarge 49 | - c3.8xlarge 50 | - c4.large 51 | - c4.xlarge 52 | - c4.2xlarge 53 | - c4.4xlarge 54 | - c4.8xlarge 55 | - c5.large 56 | - c5.xlarge 57 | - c5.2xlarge 58 | - c5.4xlarge 59 | - c5.9xlarge 60 | - c5.12xlarge 61 | - c5.18xlarge 62 | - c5.24xlarge 63 | - g2.2xlarge 64 | - g2.8xlarge 65 | - r3.large 66 | - r3.xlarge 67 | - r3.2xlarge 68 | - r3.4xlarge 69 | - r3.8xlarge 70 | - i2.xlarge 71 | - i2.2xlarge 72 | - i2.4xlarge 73 | - i2.8xlarge 74 | - d2.xlarge 75 | - d2.2xlarge 76 | - d2.4xlarge 77 | - d2.8xlarge 78 | - hi1.4xlarge 79 | - hs1.8xlarge 80 | - cr1.8xlarge 81 | - cc2.8xlarge 82 | - cg1.4xlarge 83 | ConstraintDescription: must be a valid EC2 instance type. 84 | STUNServerAddress: 85 | Description: 'STUN/TURN Server Domain Name' 86 | Type: String 87 | Default: '' 88 | UserName: 89 | Description: 'STUN/TURN Server Username' 90 | Type: String 91 | Default: '' 92 | Password: 93 | Description: 'STUN/TURN Server Password' 94 | Type: String 95 | Default: '' 96 | KeyName: 97 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). 98 | Type: 'AWS::EC2::KeyPair::KeyName' 99 | MinLength: '1' 100 | MaxLength: '255' 101 | AllowedPattern: '[\x20-\x7E]*' 102 | ConstraintDescription: can contain only ASCII characters. 103 | 104 | Resources: 105 | DescribeImagesRole: 106 | Type: AWS::IAM::Role 107 | Properties: 108 | AssumeRolePolicyDocument: 109 | Version: '2012-10-17' 110 | Statement: 111 | - Action: sts:AssumeRole 112 | Effect: Allow 113 | Principal: 114 | Service: lambda.amazonaws.com 115 | ManagedPolicyArns: 116 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 117 | Policies: 118 | - PolicyName: DescribeImages 119 | PolicyDocument: 120 | Version: '2012-10-17' 121 | Statement: 122 | - Action: ec2:DescribeImages 123 | Effect: Allow 124 | Resource: "*" 125 | GetLatestAMI: 126 | Type: AWS::Lambda::Function 127 | Properties: 128 | Runtime: python3.9 129 | Handler: index.handler 130 | Role: !Sub ${DescribeImagesRole.Arn} 131 | Timeout: 60 132 | Code: 133 | ZipFile: | 134 | import boto3 135 | import cfnresponse 136 | import json 137 | import traceback 138 | 139 | def handler(event, context): 140 | try: 141 | response = boto3.client('ec2').describe_images( 142 | Owners=[event['ResourceProperties']['Owner']], 143 | Filters=[ 144 | {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, 145 | {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, 146 | {'Name': 'root-device-type', 'Values': ['ebs']}, 147 | ], 148 | ) 149 | 150 | amis = sorted(response['Images'], 151 | key=lambda x: x['CreationDate'], 152 | reverse=True) 153 | id = amis[0]['ImageId'] 154 | 155 | cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) 156 | except: 157 | traceback.print_last() 158 | cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") 159 | 160 | UbuntuAmi: 161 | Type: Custom::FindAMI 162 | Properties: 163 | ServiceToken: !Sub ${GetLatestAMI.Arn} 164 | Owner: "099720109477" 165 | Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" 166 | Architecture: "x86_64" 167 | 168 | TurnServerSecurityGroup: 169 | Type: 'AWS::EC2::SecurityGroup' 170 | Properties: 171 | GroupDescription: Enable SSH access and HTTP access on the configured port 172 | SecurityGroupIngress: 173 | - IpProtocol: tcp 174 | FromPort: '22' 175 | ToPort: '22' 176 | CidrIp: 0.0.0.0/0 177 | - IpProtocol: tcp 178 | FromPort: '3478' 179 | ToPort: '3478' 180 | CidrIp: 0.0.0.0/0 181 | - IpProtocol: udp 182 | FromPort: '3478' 183 | ToPort: '3478' 184 | CidrIp: 0.0.0.0/0 185 | VpcId: !Ref VpcId 186 | TurnServerInstance: 187 | Type: 'AWS::EC2::Instance' 188 | Properties: 189 | KeyName: !Ref KeyName 190 | ImageId: !Ref UbuntuAmi 191 | InstanceType: !Ref TurnServerInstanceType 192 | SubnetId: !Select [ 0, !Ref Subnets ] 193 | SecurityGroupIds: 194 | - !GetAtt "TurnServerSecurityGroup.GroupId" 195 | Tags: 196 | - Key: Name 197 | Value: TurnServer 198 | UserData: 199 | Fn::Base64: 200 | !Sub | 201 | #!/bin/bash -xe 202 | apt-get update && apt-get install coturn -y 203 | sed -i 's/#TURNSERVER.*/TURNSERVER_ENABLED=1/g' /etc/default/coturn 204 | cat << EOF > /etc/turnserver.conf 205 | listening-port=3478 206 | realm=${STUNServerAddress} 207 | relay-ip=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) 208 | external-ip=$(curl -s curl http://checkip.amazonaws.com)/$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) 209 | user=${UserName}:${Password} 210 | lt-cred-mech 211 | fingerprint 212 | EOF 213 | systemctl enable coturn && systemctl restart coturn 214 | ElasticIP: 215 | Type: AWS::EC2::EIP 216 | Properties: 217 | Domain: "vpc" 218 | ElasticIPAssignment: 219 | Type: AWS::EC2::EIPAssociation 220 | Properties: 221 | EIP: !Ref ElasticIP 222 | InstanceId: !Ref TurnServerInstance 223 | Outputs: 224 | TurnServer: 225 | Description: "Do not forget to add an A record for your domain address." 226 | Value: !Join 227 | - '' 228 | - - !GetAtt 229 | - TurnServerInstance 230 | - PublicIp -------------------------------------------------------------------------------- /cloudformation/wavelength/ams-wavelength-standalone.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | Ant Media Server Standalone EC2 server template for Wavelength Zone 4 | If you have any questions, please just drop a line to contact (at) antmedia.io 5 | Parameters: 6 | AntMediaServerInstanceType: 7 | Description: Ant Media Server EC2 instance type 8 | Type: String 9 | Default: t3.medium 10 | AllowedValues: 11 | - t3.medium 12 | - t3.xlarge 13 | - r5.2xlarge 14 | - g4dn.2xlarge 15 | ConstraintDescription: must be a valid EC2 instance type. 16 | KeyName: 17 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). 18 | Type: 'AWS::EC2::KeyPair::KeyName' 19 | MinLength: '1' 20 | MaxLength: '255' 21 | AllowedPattern: '[\x20-\x7E]*' 22 | ConstraintDescription: can contain only ASCII characters. 23 | STUNServerAddress: 24 | Description: 'STUN Server Address' 25 | Type: String 26 | Default: 'stun.wavelength.antmedia.cloud' 27 | DomainName: 28 | Description: 'Fill in this field if you selected EnableSSL true. The domain name that you will use in Ant Media Server.' 29 | Type: String 30 | Default: '' 31 | Route53HostedZoneId: 32 | Description: 'Fill in this field if you selected EnableSSL true. HostedZoneId of Domain Name on Route53' 33 | Type: String 34 | Default: '' 35 | EnableSSL: 36 | Description: 'If you want to enable SSL for Ant Media Server, select True and fill in the "DomainName, Route53HostedZoneId" fields.' 37 | Default: false 38 | Type: String 39 | AllowedValues: 40 | - true 41 | - false 42 | PolicyName: 43 | Description: 'Fill in this field if you selected EnableSSL true. Policy name with Route53 access granted' 44 | Type: String 45 | Default: '' 46 | 47 | WavelengthZones: 48 | Type: String 49 | Description: '' 50 | Default: us-east-1-wl1-bos-wlz-1 51 | AllowedValues: 52 | - us-east-1-wl1-atl-wlz-1 53 | - us-east-1-wl1-bos-wlz-1 54 | - us-east-1-wl1-chi-wlz-1 55 | - us-east-1-wl1-dfw-wlz-1 56 | - us-east-1-wl1-iah-wlz-1 57 | - us-east-1-wl1-mia-wlz-1 58 | - us-east-1-wl1-nyc-wlz-1 59 | - us-east-1-wl1-was-wlz-1 60 | - us-west-2-wl1-den-wlz-1 61 | - us-west-2-wl1-las-wlz-1 62 | - us-west-2-wl1-phx-wlz-1 63 | - us-west-2-wl1-sfo-wlz-1 64 | - us-west-2-wl1-sea-wlz-1 65 | - ap-northeast-2-wl1-cjj-wlz-1 66 | - ap-northeast-1-wl1-kix-wlz-1 67 | - ap-northeast-1-wl1-nrt-wlz-1 68 | - eu-west-2-wl1-lon-wlz-1 69 | 70 | Conditions: 71 | Route53IAM: !Equals 72 | - !Ref EnableSSL 73 | - true 74 | 75 | Resources: 76 | DescribeImagesRole: 77 | Type: AWS::IAM::Role 78 | Properties: 79 | AssumeRolePolicyDocument: 80 | Version: '2012-10-17' 81 | Statement: 82 | - Action: sts:AssumeRole 83 | Effect: Allow 84 | Principal: 85 | Service: lambda.amazonaws.com 86 | ManagedPolicyArns: 87 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 88 | Policies: 89 | - PolicyName: DescribeImages 90 | PolicyDocument: 91 | Version: '2012-10-17' 92 | Statement: 93 | - Action: ec2:DescribeImages 94 | Effect: Allow 95 | Resource: "*" 96 | GetLatestAMI: 97 | Type: AWS::Lambda::Function 98 | Properties: 99 | Runtime: python3.9 100 | Handler: index.handler 101 | Role: !Sub ${DescribeImagesRole.Arn} 102 | Timeout: 60 103 | Code: 104 | ZipFile: | 105 | import boto3 106 | import cfnresponse 107 | import json 108 | import traceback 109 | 110 | def handler(event, context): 111 | try: 112 | response = boto3.client('ec2').describe_images( 113 | Owners=[event['ResourceProperties']['Owner']], 114 | Filters=[ 115 | {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, 116 | {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, 117 | {'Name': 'root-device-type', 'Values': ['ebs']}, 118 | ], 119 | ) 120 | 121 | amis = sorted(response['Images'], 122 | key=lambda x: x['CreationDate'], 123 | reverse=True) 124 | id = amis[0]['ImageId'] 125 | 126 | cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) 127 | except: 128 | traceback.print_last() 129 | cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") 130 | 131 | AntMediaAmi: 132 | Type: Custom::FindAMI 133 | Properties: 134 | ServiceToken: !Sub ${GetLatestAMI.Arn} 135 | Owner: "679593333241" 136 | Name: "AntMedia-AWS-Marketplace-EE-*" 137 | Architecture: "x86_64" 138 | 139 | UbuntuAmi: 140 | Type: Custom::FindAMI 141 | Properties: 142 | ServiceToken: !Sub ${GetLatestAMI.Arn} 143 | Owner: "099720109477" 144 | Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" 145 | Architecture: "x86_64" 146 | WavelengthVPC: 147 | Type: AWS::EC2::VPC 148 | Properties: 149 | CidrBlock: 10.0.0.0/16 150 | EnableDnsHostnames: true 151 | EnableDnsSupport: true 152 | Tags: 153 | - Key: Name 154 | Value: !Sub ${AWS::StackName}-Wavelength-Vpc 155 | 156 | Subnet: 157 | Type: AWS::EC2::Subnet 158 | DependsOn: WavelengthVPC 159 | Properties: 160 | VpcId: !Ref WavelengthVPC 161 | AvailabilityZone: !Ref WavelengthZones 162 | CidrBlock: 10.0.1.0/24 163 | Tags: 164 | - Key: Name 165 | Value: !Sub ${AWS::StackName}-Wavelength-Origin-Subnet 166 | 167 | CarrierDefaultGateway: 168 | Type: AWS::EC2::CarrierGateway 169 | Properties: 170 | VpcId: !Ref WavelengthVPC 171 | 172 | CarrierDefaultRouteTable: 173 | Type: AWS::EC2::RouteTable 174 | Properties: 175 | VpcId: !Ref WavelengthVPC 176 | Tags: 177 | - Key: Name 178 | Value: !Sub ${AWS::StackName}-Wavelength-Route-Table 179 | 180 | DefaultRoute: 181 | Type: AWS::EC2::Route 182 | DependsOn: CarrierDefaultGateway 183 | Properties: 184 | RouteTableId: !Ref CarrierDefaultRouteTable 185 | CarrierGatewayId: !Ref CarrierDefaultGateway 186 | DestinationCidrBlock: 0.0.0.0/0 187 | 188 | SubnetRouteTableAssociationOrigin: 189 | Type: AWS::EC2::SubnetRouteTableAssociation 190 | Properties: 191 | RouteTableId: !Ref CarrierDefaultRouteTable 192 | SubnetId: !Ref Subnet 193 | 194 | 195 | InstanceSecurityGroup: 196 | Type: 'AWS::EC2::SecurityGroup' 197 | Properties: 198 | GroupDescription: Enable SSH access and HTTP access on the configured port 199 | SecurityGroupIngress: 200 | - IpProtocol: tcp 201 | FromPort: '22' 202 | ToPort: '22' 203 | CidrIp: 0.0.0.0/0 204 | - IpProtocol: tcp 205 | FromPort: '5080' 206 | ToPort: '5080' 207 | CidrIp: 0.0.0.0/0 208 | - IpProtocol: tcp 209 | FromPort: '5443' 210 | ToPort: '5443' 211 | CidrIp: 0.0.0.0/0 212 | - IpProtocol: tcp 213 | FromPort: '1935' 214 | ToPort: '1935' 215 | CidrIp: 0.0.0.0/0 216 | - IpProtocol: udp 217 | FromPort: '5000' 218 | ToPort: '65000' 219 | CidrIp: 0.0.0.0/0 220 | VpcId: !Ref WavelengthVPC 221 | AntMediaEC2Instance: 222 | Type: 'AWS::EC2::Instance' 223 | Properties: 224 | KeyName: !Ref KeyName 225 | ImageId: !Ref AntMediaAmi 226 | InstanceType: !Ref AntMediaServerInstanceType 227 | NetworkInterfaces: 228 | - AssociateCarrierIpAddress: true 229 | IamInstanceProfile: !If [Route53IAM, !Ref PolicyName, !Ref "AWS::NoValue"] 230 | NetworkInterfaces: 231 | - SubnetId: !Ref Subnet 232 | AssociateCarrierIpAddress: true 233 | DeviceIndex: '0' 234 | GroupSet: 235 | - Ref: InstanceSecurityGroup 236 | Tags: 237 | - Key: Name 238 | Value: AntmediaServer 239 | UserData: 240 | Fn::Base64: 241 | !Sub | 242 | #!/bin/bash -xe 243 | apt-get update && apt-get install awscli -y 244 | sed -i "s/stun1.l.google.com:19302/${STUNServerAddress}/g" /usr/local/antmedia/webapps/WebRTCAppEE/*.html 245 | if [ ${EnableSSL} == "true" ]; then 246 | cat << EOF > /tmp/aws_route53.json 247 | { 248 | "Comment": "CREATE/DELETE/UPSERT a record ", 249 | "Changes": [{ 250 | "Action": "CREATE", 251 | "ResourceRecordSet": { 252 | "Name":"${DomainName}", 253 | "Type": "A", 254 | "TTL": 300, 255 | "ResourceRecords": [{ "Value":"$(curl -s http://checkip.amazonaws.com)"}] 256 | }}]} 257 | EOF 258 | aws route53 change-resource-record-sets --hosted-zone-id ${Route53HostedZoneId} --change-batch file:///tmp/aws_route53.json 259 | bash /usr/local/antmedia/enable_ssl.sh -d ${DomainName} -v route53 260 | fi 261 | 262 | -------------------------------------------------------------------------------- /cloudformation/wavelength/stunserver.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | TurnServer Installation 4 | Parameters: 5 | Subnets: 6 | Type: 'List' 7 | Description: 'You must choose at least 2 subnets from the same VPC network.' 8 | ConstraintDescription: >- 9 | must be a list of at least two existing subnets associated with at least 10 | two different availability zones. They should be residing in the selected 11 | Virtual Private Cloud. 12 | VpcId: 13 | Type: 'AWS::EC2::VPC::Id' 14 | Description: 'VpcId of your existing Virtual Private Cloud (VPC). The VpcId must be the same as the subnets you choose' 15 | ConstraintDescription: 'must be the VPC Id of an existing Virtual Private Cloud. The VpcId must be the same as the subnets you choose.' 16 | TurnServerInstanceType: 17 | Description: Ant Media Server Edge EC2 instance type 18 | Type: String 19 | Default: t3.medium 20 | AllowedValues: 21 | - t3.medium 22 | - t3.xlarge 23 | - r5.2xlarge 24 | ConstraintDescription: must be a valid EC2 instance type. 25 | STUNServerAddress: 26 | Description: 'STUN Server Address' 27 | Type: String 28 | Default: '' 29 | KeyName: 30 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). 31 | Type: 'AWS::EC2::KeyPair::KeyName' 32 | MinLength: '1' 33 | MaxLength: '255' 34 | AllowedPattern: '[\x20-\x7E]*' 35 | ConstraintDescription: can contain only ASCII characters. 36 | 37 | Resources: 38 | DescribeImagesRole: 39 | Type: AWS::IAM::Role 40 | Properties: 41 | AssumeRolePolicyDocument: 42 | Version: '2012-10-17' 43 | Statement: 44 | - Action: sts:AssumeRole 45 | Effect: Allow 46 | Principal: 47 | Service: lambda.amazonaws.com 48 | ManagedPolicyArns: 49 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 50 | Policies: 51 | - PolicyName: DescribeImages 52 | PolicyDocument: 53 | Version: '2012-10-17' 54 | Statement: 55 | - Action: ec2:DescribeImages 56 | Effect: Allow 57 | Resource: "*" 58 | GetLatestAMI: 59 | Type: AWS::Lambda::Function 60 | Properties: 61 | Runtime: python3.6 62 | Handler: index.handler 63 | Role: !Sub ${DescribeImagesRole.Arn} 64 | Timeout: 60 65 | Code: 66 | ZipFile: | 67 | import boto3 68 | import cfnresponse 69 | import json 70 | import traceback 71 | 72 | def handler(event, context): 73 | try: 74 | response = boto3.client('ec2').describe_images( 75 | Owners=[event['ResourceProperties']['Owner']], 76 | Filters=[ 77 | {'Name': 'name', 'Values': [event['ResourceProperties']['Name']]}, 78 | {'Name': 'architecture', 'Values': [event['ResourceProperties']['Architecture']]}, 79 | {'Name': 'root-device-type', 'Values': ['ebs']}, 80 | ], 81 | ) 82 | 83 | amis = sorted(response['Images'], 84 | key=lambda x: x['CreationDate'], 85 | reverse=True) 86 | id = amis[0]['ImageId'] 87 | 88 | cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, id) 89 | except: 90 | traceback.print_last() 91 | cfnresponse.send(event, context, cfnresponse.FAIL, {}, "ok") 92 | 93 | UbuntuAmi: 94 | Type: Custom::FindAMI 95 | Properties: 96 | ServiceToken: !Sub ${GetLatestAMI.Arn} 97 | Owner: "099720109477" 98 | Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" 99 | Architecture: "x86_64" 100 | 101 | TurnServerSecurityGroup: 102 | Type: 'AWS::EC2::SecurityGroup' 103 | Properties: 104 | GroupDescription: Enable SSH access and HTTP access on the configured port 105 | SecurityGroupIngress: 106 | - IpProtocol: tcp 107 | FromPort: '22' 108 | ToPort: '22' 109 | CidrIp: 0.0.0.0/0 110 | - IpProtocol: tcp 111 | FromPort: '3478' 112 | ToPort: '3478' 113 | CidrIp: 0.0.0.0/0 114 | - IpProtocol: udp 115 | FromPort: '3478' 116 | ToPort: '3478' 117 | CidrIp: 0.0.0.0/0 118 | - IpProtocol: udp 119 | FromPort: '80' 120 | ToPort: '80' 121 | CidrIp: 0.0.0.0/0 122 | VpcId: !Ref VpcId 123 | TurnServerInstance: 124 | Type: 'AWS::EC2::Instance' 125 | Properties: 126 | KeyName: !Ref KeyName 127 | ImageId: !Ref UbuntuAmi 128 | InstanceType: !Ref TurnServerInstanceType 129 | NetworkInterfaces: 130 | - AssociateCarrierIpAddress: true 131 | NetworkInterfaces: 132 | - SubnetId: !Select [ 0, !Ref Subnets ] 133 | AssociateCarrierIpAddress: true 134 | DeviceIndex: '0' 135 | GroupSet: 136 | - Ref: TurnServerSecurityGroup 137 | Tags: 138 | - Key: Name 139 | Value: TurnServer 140 | UserData: 141 | Fn::Base64: 142 | !Sub | 143 | #!/bin/bash -xe 144 | apt-get update && apt-get install coturn -y 145 | sed -i 's/#TURNSERVER.*/TURNSERVER_ENABLED=1/g' /etc/default/coturn 146 | cat << EOF > /etc/turnserver.conf 147 | listening-port=3478 148 | realm=${STUNServerAddress} 149 | relay-ip=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) 150 | external-ip=$(curl -s curl http://checkip.amazonaws.com)/$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) 151 | fingerprint 152 | EOF 153 | systemctl enable coturn && systemctl restart coturn 154 | 155 | 156 | -------------------------------------------------------------------------------- /cloudformation/wavelength/wavelength-vpc.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | You can create 2 subnets in the Wavelength zone and assign Carrier Gateway with this template. 4 | Parameters: 5 | VpcCidrBlock: 6 | Description: 'CIDR value for Wavelength Network' 7 | Type: String 8 | MinLength: '9' 9 | MaxLength: '18' 10 | Default: 10.0.0.0/16 11 | AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' 12 | ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. 13 | OriginCidrBlock: 14 | Description: 'CIDR value of Origin' 15 | Type: String 16 | MinLength: '9' 17 | MaxLength: '18' 18 | Default: 10.0.1.0/24 19 | AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' 20 | EdgeCidrBlock: 21 | Description: 'CIDR value of Edge' 22 | Type: String 23 | MinLength: '9' 24 | MaxLength: '18' 25 | Default: 10.0.2.0/24 26 | AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' 27 | WavelengthZones: 28 | Type: String 29 | Description: '' 30 | Default: us-east-1-wl1-bos-wlz-1 31 | AllowedValues: 32 | - us-east-1-wl1-atl-wlz-1 33 | - us-east-1-wl1-bos-wlz-1 34 | - us-east-1-wl1-chi-wlz-1 35 | - us-east-1-wl1-dfw-wlz-1 36 | - us-east-1-wl1-iah-wlz-1 37 | - us-east-1-wl1-mia-wlz-1 38 | - us-east-1-wl1-nyc-wlz-1 39 | - us-east-1-wl1-was-wlz-1 40 | - us-west-2-wl1-den-wlz-1 41 | - us-west-2-wl1-las-wlz-1 42 | - us-west-2-wl1-phx-wlz-1 43 | - us-west-2-wl1-sfo-wlz-1 44 | - us-west-2-wl1-sea-wlz-1 45 | - ap-northeast-2-wl1-cjj-wlz-1 46 | - ap-northeast-1-wl1-kix-wlz-1 47 | - ap-northeast-1-wl1-nrt-wlz-1 48 | - eu-west-2-wl1-lon-wlz-1 49 | KeyName: 50 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. If there is no value here, you must create an ssh key (EC2 > Key Pairs). 51 | Type: 'AWS::EC2::KeyPair::KeyName' 52 | MinLength: '1' 53 | MaxLength: '255' 54 | AllowedPattern: '[\x20-\x7E]*' 55 | ConstraintDescription: can contain only ASCII characters. 56 | 57 | Resources: 58 | WavelengthVPC: 59 | Type: AWS::EC2::VPC 60 | Properties: 61 | CidrBlock: !Ref VpcCidrBlock 62 | EnableDnsHostnames: true 63 | EnableDnsSupport: true 64 | Tags: 65 | - Key: Name 66 | Value: !Sub ${AWS::StackName}-Wavelength-Vpc 67 | 68 | OriginZone: 69 | Type: AWS::EC2::Subnet 70 | DependsOn: WavelengthVPC 71 | Properties: 72 | VpcId: !Ref WavelengthVPC 73 | AvailabilityZone: !Ref WavelengthZones 74 | CidrBlock: !Ref OriginCidrBlock 75 | Tags: 76 | - Key: Name 77 | Value: !Sub ${AWS::StackName}-Wavelength-Origin-Subnet 78 | 79 | EdgeZone: 80 | Type: AWS::EC2::Subnet 81 | DependsOn: WavelengthVPC 82 | Properties: 83 | VpcId: !Ref WavelengthVPC 84 | AvailabilityZone: !Ref WavelengthZones 85 | CidrBlock: !Ref EdgeCidrBlock 86 | Tags: 87 | - Key: Name 88 | Value: !Sub ${AWS::StackName}-Wavelength-Edge-Subnet 89 | 90 | CarrierDefaultGateway: 91 | Type: AWS::EC2::CarrierGateway 92 | Properties: 93 | VpcId: !Ref WavelengthVPC 94 | 95 | CarrierDefaultRouteTable: 96 | Type: AWS::EC2::RouteTable 97 | Properties: 98 | VpcId: !Ref WavelengthVPC 99 | Tags: 100 | - Key: Name 101 | Value: !Sub ${AWS::StackName}-Wavelength-Route-Table 102 | 103 | DefaultRoute: 104 | Type: AWS::EC2::Route 105 | DependsOn: CarrierDefaultGateway 106 | Properties: 107 | RouteTableId: !Ref CarrierDefaultRouteTable 108 | CarrierGatewayId: !Ref CarrierDefaultGateway 109 | DestinationCidrBlock: 0.0.0.0/0 110 | 111 | SubnetRouteTableAssociationOrigin: 112 | Type: AWS::EC2::SubnetRouteTableAssociation 113 | Properties: 114 | RouteTableId: !Ref CarrierDefaultRouteTable 115 | SubnetId: !Ref OriginZone 116 | 117 | SubnetRouteTableAssociationEdge: 118 | Type: AWS::EC2::SubnetRouteTableAssociation 119 | Properties: 120 | RouteTableId: !Ref CarrierDefaultRouteTable 121 | SubnetId: !Ref EdgeZone 122 | -------------------------------------------------------------------------------- /docker/Dockerfile_Process: -------------------------------------------------------------------------------- 1 | # 2 | # This docker file can be used in kubernetes. 3 | # It accepts all cluster related parameters at run time. 4 | # It means it's very easy to add new containers to the cluster 5 | # 6 | # Usage: 7 | # 8 | # * AntMediaServer: Specify the name of the Ant Media Server zip file to install that specify Ant Media Server version to the docker image 9 | # --build-arg AntMediaServer='ant-media-server.zip' 10 | # 11 | # * LicenseKey: Set your license key to this variable to install the latest Ant Media Server automatically to the docker image without needing a zip file. If you use this LicenseKey variable, don't specify AntMediaServer variable (# --build-arg AntMediaServer='ant-media-server.zip') 12 | # --build-arg LicenseKey='your-license-key' 13 | # 14 | # * InstallMediaPush: Set this variable to 'true' to enable headless Chrome on the server for recording and streaming web pages back to Ant Media Server. 15 | # --build-arg InstallMediaPush='true' 16 | # 17 | # * MediaPushVersion: Specify the latest version or latest snapshot version of the Media Push Plugin. It's empty by default and the latest version of the Media Push Plugin will be installed by default. 18 | # If you want to install the latest snapshot version of the Media Push Plugin, you can specify --snapshot 19 | # 20 | # --build-arg MediaPushVersion='--snapshot' 21 | # 22 | # * Supervisor Configuration (Optional): If you want to use Supervisor to manage the Ant Media Server process, you can enable as follows. With this configuration, you can easily restart, stop the service, or run the `enable_ssl.sh` script for Ant Media Server. 23 | # --build-arg UseSupervisor='true' 24 | # 25 | 26 | FROM ubuntu:22.04 27 | 28 | ARG AntMediaServer 29 | ARG LicenseKey 30 | ARG InstallMediaPush 31 | ARG MediaPushVersion 32 | ARG UseSupervisor=false 33 | ARG BranchName=master 34 | 35 | ENV UseSupervisor=${UseSupervisor} 36 | 37 | #Running update and install makes the builder not to use cache which resolves some updates 38 | RUN apt-get update && apt-get install -y curl wget iproute2 cron logrotate dnsutils iptables 39 | 40 | ADD ./${AntMediaServer} /home 41 | 42 | RUN cd home \ 43 | && pwd \ 44 | && wget https://raw.githubusercontent.com/ant-media/Scripts/${BranchName}/install_ant-media-server.sh \ 45 | && chmod 755 install_ant-media-server.sh 46 | 47 | RUN cd /home \ 48 | && pwd \ 49 | && if [ -n "$AntMediaServer" ]; then \ 50 | ./install_ant-media-server.sh -i ${AntMediaServer} -s false; \ 51 | elif [ -n "$LicenseKey" ]; then \ 52 | ./install_ant-media-server.sh -l ${LicenseKey} -s false; \ 53 | else \ 54 | echo "Both AntMediaServer and LicenseKey arguments are not provided. Aborting the build process."; \ 55 | exit 1; \ 56 | fi 57 | 58 | RUN if [ "true" = "$InstallMediaPush" ]; then \ 59 | echo "test"; \ 60 | echo "#!/bin/bash\n\$@" > /usr/bin/sudo; \ 61 | chmod +x /usr/bin/sudo; \ 62 | wget -O install_media-push-plugin.sh https://raw.githubusercontent.com/ant-media/Plugins/master/MediaPushPlugin/src/main/script/install_media-push-plugin.sh; \ 63 | bash ./install_media-push-plugin.sh $MediaPushVersion; \ 64 | fi 65 | 66 | # 67 | # Options: 68 | # 69 | # -g: Use global(Public) IP in network communication. Its value can be true or false. Default value is false. 70 | # 71 | # -s: Use Public IP as server name. Its value can be true or false. Default value is false. 72 | # 73 | # -r: Replace candidate address with server name. Its value can be true or false. Default value is false 74 | # 75 | # -m: Server mode. It can be standalone or cluster. If cluster mode is specified then mongodb host, username and password should also be provided. 76 | # There is no default value for mode 77 | # 78 | # -h: MongoDB or Redist host. It's either IP address or full connection string such as mongodb://[username:password@]host1[:port1] or mongodb+srv://[username:password@]host1[:port1] or redis://[username:password@]host1[:port1] or redis yaml configuration 79 | # 80 | # -u: MongoDB username: Deprecated. Just give the username in the connection string with -h parameter 81 | # 82 | # -p: MongoDB password: Deprecated. Just give the password in the connection string with -h parameter 83 | # 84 | # -l: Licence Key 85 | 86 | # -a: TURN/STUN Server URL for the server side. It should start with "turn:" or "stun:" such as stun:stun.l.google.com:19302 or turn:ovh36.antmedia.io 87 | # this url is not visible to frontend users just for server side. 88 | # 89 | # -n: TURN Server Usermame: Provide the TURN server username to get relay candidates. 90 | # 91 | # -w: TURN Server Password: Provide the TURN server password to get relay candidates. 92 | # 93 | # -k: Kafka Address: Provide the Kafka URL address to collect data. (It must contain the port number. Example: localhost:9092) 94 | # 95 | # -j: JVM Memory Options(-Xms1g -Xmx4g): Set the Java heap size. Default value is "-Xms1g". Example usage: ./start.sh -j "-Xms1g -Xmx4g" 96 | # 97 | # -c: CPU Limit: Set the CPU limit percentage that server does not exceed. Default value is 75. 98 | # If CPU is more than this value, server reports highResourceUsage and does not allow publish or play. 99 | # Example usage: ./start.sh -c 60 100 | # 101 | # -e: Memory Limit: Set the Memory Limit percentage that server does not exceed. Default value is 75 102 | # If Memory usage is more than this value, server reports highResourceUsage and does not allow publish or play 103 | # Example usage: ./start.sh -e 60 104 | 105 | 106 | ##################### supervisor configuration ############################## 107 | RUN if [ "true" = "$UseSupervisor" ]; then \ 108 | apt-get update && apt-get install -y supervisor && \ 109 | echo '[supervisord]\n\ 110 | nodaemon=true\n\ 111 | \n\ 112 | [program:antmedia]\n\ 113 | command=/bin/bash -c "/usr/local/antmedia/start.sh $@"\n\ 114 | autostart=true\n\ 115 | autorestart=true\n\ 116 | user=antmedia\n\ 117 | stdout_logfile_maxbytes = 0\n\ 118 | stderr_logfile_maxbytes = 0\n\ 119 | stdout_logfile=/dev/stdout\n\ 120 | stderr_logfile=/dev/stderr' > /etc/supervisor/supervisord.conf; \ 121 | fi 122 | 123 | ############################################################################## 124 | 125 | ENTRYPOINT [ "sh", "-c", "if [ \"$UseSupervisor\" = \"true\" ]; then exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf; else exec /usr/local/antmedia/start.sh \"$@\"; fi", "--" ] 126 | -------------------------------------------------------------------------------- /docker/Dockerfile_RockyLinux: -------------------------------------------------------------------------------- 1 | FROM rockylinux/rockylinux:9.3 2 | ARG AntMediaServer 3 | 4 | ARG BranchName=master 5 | 6 | #Running update and install makes the builder not to use cache which resolves some updates 7 | RUN yum install -y curl wget iproute logrotate which findutils which crontabs unzip --allowerasing 8 | 9 | ADD ./${AntMediaServer} /home 10 | 11 | RUN cd home \ 12 | && pwd \ 13 | && wget https://raw.githubusercontent.com/ant-media/Scripts/${BranchName}/install_ant-media-server.sh \ 14 | && chmod 755 install_ant-media-server.sh 15 | 16 | RUN cd home \ 17 | && pwd \ 18 | && ./install_ant-media-server.sh -i ${AntMediaServer} -s false 19 | 20 | 21 | # Options 22 | # -g: Use global(Public) IP in network communication. Its value can be true or false. Default value is false. 23 | # 24 | # -s: Use Public IP as server name. Its value can be true or false. Default value is false. 25 | # 26 | # -r: Replace candidate address with server name. Its value can be true or false. Default value is false 27 | # 28 | # -m: Server mode. It can be standalone or cluster. If cluster mode is specified then mongodb host, username and password should also be provided. 29 | # There is no default value for mode 30 | # 31 | # -h: MongoDB or Redist host. It's either IP address or full connection string such as mongodb://[username:password@]host1[:port1] or mongodb+srv://[username:password@]host1[:port1] or redis://[username:password@]host1[:port1] or redis yaml configuration 32 | # 33 | # -u: MongoDB username: Deprecated. Just give the username in the connection string with -h parameter 34 | # 35 | # -p: MongoDB password: Deprecated. Just give the password in the connection string with -h parameter 36 | # 37 | # -l: Licence Key 38 | 39 | # -a: TURN/STUN Server URL for the server side. It should start with "turn:" or "stun:" such as stun:stun.l.google.com:19302 or turn:ovh36.antmedia.io 40 | # this url is not visible to frontend users just for server side. 41 | # 42 | # -n: TURN Server Usermame: Provide the TURN server username to get relay candidates. 43 | # 44 | # -w: TURN Server Password: Provide the TURN server password to get relay candidates. 45 | 46 | ENTRYPOINT ["/usr/local/antmedia/start.sh"] 47 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | antmedia: 4 | build: 5 | context: ./ 6 | dockerfile: ./Dockerfile 7 | container_name: antmedia 8 | restart: unless-stopped 9 | entrypoint: /usr/local/antmedia/start.sh 10 | network_mode: host 11 | # volumes: 12 | # - antmedia_vol:/usr/local/antmedia/ 13 | #volumes: 14 | # antmedia_vol: 15 | # external: true 16 | # name: 17 | # antmedia_volume 18 | -------------------------------------------------------------------------------- /easy_ssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo '''{ 4 | "Comment": "CREATE/DELETE/UPSERT a record ", 5 | "Changes": [{ 6 | "Action": "CREATE", 7 | "ResourceRecordSet": { 8 | "Name":"test.antmedia.cloud", 9 | "Type": "A", 10 | "TTL": 300, 11 | "ResourceRecords": [{ "Value":"1.1.1.1"}] 12 | }}]}''' > aws_a.json 13 | 14 | aws_env=$(<.env) 15 | AWS_ACCESS_KEY=`echo $aws_env | awk '{print $1}'` 16 | AWS_SECRET_KEY=`echo $aws_env | awk '{print $2}'` 17 | AWS_JSON="aws_a.json" 18 | 19 | #aws 20 | if [ -z `which aws2` ]; then 21 | rm -r aws* > /dev/null 2>&1 22 | echo "Please wait. AWS Client is installing..." 23 | curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" > /dev/null 2>&1 24 | unzip awscliv2.zip > /dev/null 2>&1 25 | sudo ./aws/install & 26 | wait $! 27 | echo "AWS Client installed." 28 | rm -r aws* 29 | fi 30 | 31 | #Aws Configuration 32 | 33 | aws2 configure set aws_access_key_id $AWS_ACCESS_KEY 34 | aws2 configure set aws_secret_access_key $AWS_SECRET_KEY 35 | aws2 configure set output json 36 | 37 | usage() { 38 | 39 | echo "" 40 | echo "Usage: " 41 | echo "-k ssh key" 42 | echo "-u username" 43 | echo "-i ip addrress" 44 | echo "-d subdomain name (test01.antmedia.cloud)" 45 | 46 | } 47 | 48 | if [ "$#" -eq 0 ]; then 49 | usage 50 | fi 51 | 52 | while getopts k:u:i:d: option 53 | do 54 | case "${option}" 55 | in 56 | k) k=${OPTARG};; 57 | u) u=${OPTARG};; 58 | i) i=${OPTARG};; 59 | d) d=${OPTARG};; 60 | esac 61 | done 62 | 63 | 64 | 65 | if [[ ! -z $k && ! -z $u && ! -z $i && ! -z $d ]]; then 66 | if [ ! -f $k ]; then 67 | echo "SSH key doesn't exist." 68 | exit 1 69 | elif [ ! -f $AWS_JSON ]; then 70 | echo "AWS Json file doesn't exist." 71 | fi 72 | check=`aws2 route53 list-resource-record-sets --hosted-zone-id Z3BEXQLL4B8OB1 | grep "Name" | awk '{print $2}' | sed ''s/^.//';s/...$//'` 73 | for c in $check; do 74 | if [ "$c" == "$d" ]; then 75 | echo "Subdomain exists" 76 | exit 1 77 | fi 78 | done 79 | 80 | #json file 81 | sed -i 's^"Name".*^"Name":'\"$d\",'^' $AWS_JSON 82 | sed -i 's^"Value":.*^"Value":'\"$i\"}]'^' $AWS_JSON 83 | sleep 1 84 | 85 | #create dns record 86 | echo "Creating DNS Record" 87 | aws2 route53 change-resource-record-sets --hosted-zone-id Z3BEXQLL4B8OB1 --change-batch file://$AWS_JSON 88 | while [ -z $(dig +short $d @8.8.8.8) ]; do 89 | now=$(date +"%H:%M:%S") 90 | echo "$now > Please wait: dns failure" 91 | sleep 10 92 | done 93 | echo "Dns success" 94 | #ssl install script 95 | echo "Installing SSL Certificate" 96 | ssh -i $k $u@$i "sudo bash /usr/local/antmedia/enable_ssl.sh -d $d" 97 | 98 | fi 99 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-firewall-template.jinja: -------------------------------------------------------------------------------- 1 | {# 2 | Copyright 2016 Google Inc. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | #} 15 | 16 | resources: 17 | - type: compute.v1.firewall 18 | name: ams-mongodb-internal 19 | properties: 20 | network: $(ref.antmedia-vpc-network.selfLink) 21 | sourceRanges: 22 | - 10.0.0.0/16 23 | targetTags: 24 | - antmedia-mongodb 25 | allowed: 26 | - IPProtocol: tcp 27 | ports: 28 | - "27017" 29 | - "22" 30 | 31 | - type: compute.v1.firewall 32 | name: ams-antmedia-external 33 | properties: 34 | network: $(ref.antmedia-vpc-network.selfLink) 35 | sourceRanges: 36 | - 0.0.0.0/0 37 | targetTags: 38 | - antmedia 39 | allowed: 40 | - IPProtocol: tcp 41 | ports: 42 | - "5080" 43 | - "22" 44 | - "1935" 45 | 46 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-instance-group-template.jinja: -------------------------------------------------------------------------------- 1 | resources: 2 | - name: origin-instance-group 3 | type: compute.v1.instanceGroupManager 4 | properties: 5 | zone: {{ properties["zone"] }} 6 | targetSize: 1 7 | baseInstanceName: antmedia-origin 8 | instanceTemplate: projects/{{ env["project"] }}/global/instanceTemplates/ams-origin-template 9 | namedPorts: 10 | - name: http 11 | port: 5080 12 | metadata: 13 | dependsOn: 14 | - ams-origin-template 15 | 16 | - name: origin-autoscaler 17 | type: compute.v1.autoscaler 18 | properties: 19 | zone: {{ properties["zone"] }} 20 | target: $(ref.origin-instance-group.selfLink) 21 | autoscalingPolicy: 22 | minNumReplicas: 1 23 | maxNumReplicas: 10 24 | coolDownPeriodSec: 60 25 | cpuUtilization: 26 | utilizationTarget: 0.6 27 | 28 | - name: edge-instance-group 29 | type: compute.v1.instanceGroupManager 30 | properties: 31 | zone: {{ properties["zone"] }} 32 | targetSize: 1 33 | baseInstanceName: antmedia-edge 34 | instanceTemplate: projects/{{ env["project"] }}/global/instanceTemplates/ams-edge-template 35 | namedPorts: 36 | - name: http 37 | port: 5080 38 | metadata: 39 | dependsOn: 40 | - ams-edge-template 41 | 42 | - name: edge-autoscaler 43 | type: compute.v1.autoscaler 44 | properties: 45 | zone: {{ properties["zone"] }} 46 | target: $(ref.edge-instance-group.selfLink) 47 | autoscalingPolicy: 48 | minNumReplicas: 1 49 | maxNumReplicas: 10 50 | coolDownPeriodSec: 60 51 | cpuUtilization: 52 | utilizationTarget: 0.6 53 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-instance-template.jinja: -------------------------------------------------------------------------------- 1 | resources: 2 | - name: ams-origin-template 3 | type: compute.v1.instanceTemplate 4 | properties: 5 | properties: 6 | zone: {{ properties["zone"] }} 7 | machineType: {{ properties["origin_machine_type"] }} 8 | metadata: 9 | items: 10 | - key: startup-script 11 | value: |- 12 | #!/bin/bash 13 | rm -rf /usr/local/antmedia/conf/instanceId 14 | rm -rf /usr/local/antmedia/*.db.* 15 | rm -rf /usr/local/antmedia/*.db 16 | cd /usr/local/antmedia 17 | ./change_server_mode.sh cluster $(ref.{{ env["deployment"] }}-mongodb.networkInterfaces[0].networkIP) 18 | disks: 19 | - deviceName: boot 20 | type: PERSISTENT 21 | boot: true 22 | autoDelete: true 23 | initializeParams: 24 | sourceImage: projects/{{ env["project"] }}/global/images/{{ properties["image_id"] }} 25 | networkInterfaces: 26 | - network: $(ref.antmedia-vpc-network.selfLink) 27 | subnetwork: $(ref.origin-subnet.selfLink) 28 | accessConfigs: 29 | - name: External NAT 30 | type: ONE_TO_ONE_NAT 31 | tags: 32 | items: 33 | - antmedia 34 | - name: ams-edge-template 35 | type: compute.v1.instanceTemplate 36 | properties: 37 | properties: 38 | zone: {{ properties["zone"] }} 39 | machineType: {{ properties["edge_machine_type"] }} 40 | metadata: 41 | items: 42 | - key: startup-script 43 | value: |- 44 | #!/bin/bash 45 | rm -rf /usr/local/antmedia/conf/instanceId 46 | rm -rf /usr/local/antmedia/*.db.* 47 | rm -rf /usr/local/antmedia/*.db 48 | cd /usr/local/antmedia 49 | ./change_server_mode.sh cluster $(ref.{{ env["deployment"] }}-mongodb.networkInterfaces[0].networkIP) 50 | disks: 51 | - deviceName: boot 52 | type: PERSISTENT 53 | boot: true 54 | autoDelete: true 55 | initializeParams: 56 | sourceImage: projects/{{ env["project"] }}/global/images/{{ properties["image_id"] }} 57 | networkInterfaces: 58 | - network: $(ref.antmedia-vpc-network.selfLink) 59 | subnetwork: $(ref.edge-subnet.selfLink) 60 | accessConfigs: 61 | - name: External NAT 62 | type: ONE_TO_ONE_NAT 63 | tags: 64 | items: 65 | - antmedia 66 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-loadbalancer-template.jinja: -------------------------------------------------------------------------------- 1 | {% set scenarios = ['origin', 'edge'] %} 2 | 3 | 4 | resources: 5 | {% for scenario in scenarios %} 6 | - name: ams-load-balancer-{{ scenario }} 7 | type: compute.v1.globalForwardingRule 8 | properties: 9 | region: {{ properties["region"] }} 10 | loadBalancingScheme: EXTERNAL 11 | target: $(ref.ams-target-proxy-{{ scenario }}.selfLink) 12 | IPAddress: $(ref.lb-ipaddress-{{ scenario }}.address) 13 | IPProtocol: TCP 14 | portRange: 443-443 15 | 16 | - name: ams-target-proxy-{{ scenario }} 17 | type: compute.v1.targetHttpsProxy 18 | properties: 19 | urlMap: $(ref.ams-{{ scenario }}.selfLink) 20 | sslCertificates: 21 | - $(ref.ams-ssl-cert-{{ scenario }}.selfLink) 22 | 23 | - name: lb-ipaddress-{{ scenario }} 24 | type: compute.v1.globalAddress 25 | 26 | - name: ams-{{ scenario }} 27 | type: compute.v1.urlMap 28 | properties: 29 | defaultService: $(ref.ams-backend-{{ scenario }}.selfLink) 30 | 31 | - name: ams-ssl-cert-{{ scenario }} 32 | type: compute.v1.sslCertificate 33 | properties: 34 | certificate: | 35 | -----BEGIN CERTIFICATE----- 36 | 37 | -----END CERTIFICATE----- 38 | privateKey: | 39 | -----BEGIN PRIVATE KEY----- 40 | 41 | -----END PRIVATE KEY----- 42 | 43 | 44 | - name: ams-backend-{{ scenario }} 45 | type: compute.v1.backendService 46 | properties: 47 | port: 5080 48 | portName: http 49 | protocol: HTTP 50 | backends: 51 | - name: backend 52 | balancingMode: UTILIZATION 53 | capacityScaler: 1.0 54 | group: projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/instanceGroups/{{ scenario }}-instance-group 55 | 56 | maxUtilization: 0.8 57 | connectionDraining: 58 | drainingTimeoutSec: 300 59 | healthChecks: 60 | - $(ref.ams-health-check-{{ scenario }}.selfLink) 61 | metadata: 62 | dependsOn: 63 | - {{ scenario }}-instance-group 64 | - ams-health-check-{{ scenario }} 65 | 66 | - name: ams-health-check-{{ scenario }} 67 | type: compute.v1.healthCheck 68 | properties: 69 | type: HTTP 70 | httpHealthCheck: 71 | port: 5080 72 | requestPath: / 73 | 74 | {% endfor %} 75 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-mongodb-template.jinja: -------------------------------------------------------------------------------- 1 | {# 2 | Copyright 2016 Google Inc. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | #} 15 | 16 | resources: 17 | - type: compute.v1.instance 18 | name: {{ env["deployment"] }}-mongodb 19 | properties: 20 | zone: {{ properties["zone"] }} 21 | machineType: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/machineTypes/{{ properties["machine_type"] }} 22 | metadata: 23 | items: 24 | # For more ways to use startup scripts on an instance, see: 25 | # https://cloud.google.com/compute/docs/startupscript 26 | - key: startup-script 27 | value: | 28 | #!/bin/bash 29 | wget https://raw.githubusercontent.com/ant-media/Scripts/master/install_mongodb.sh 30 | bash ./install_mongodb.sh 31 | disks: 32 | - deviceName: boot 33 | type: PERSISTENT 34 | boot: true 35 | autoDelete: true 36 | initializeParams: 37 | sourceImage: https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts 38 | networkInterfaces: 39 | - network: $(ref.antmedia-vpc-network.selfLink) 40 | subnetwork: $(ref.origin-subnet.selfLink) 41 | # Access Config required to give the instance a public IP address 42 | accessConfigs: 43 | - name: External NAT 44 | type: ONE_TO_ONE_NAT 45 | tags: 46 | items: 47 | - antmedia-mongodb 48 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia-vpc-template.jinja: -------------------------------------------------------------------------------- 1 | resources: 2 | - name: antmedia-vpc-network 3 | type: compute.v1.network 4 | properties: 5 | region: {{ properties["region"] }} 6 | autoCreateSubnetworks: false 7 | 8 | - name: origin-subnet 9 | type: compute.v1.subnetwork 10 | properties: 11 | ipCidrRange: 10.0.1.0/24 12 | network: $(ref.antmedia-vpc-network.selfLink) 13 | region: {{ properties["region"] }} 14 | 15 | - name: edge-subnet 16 | type: compute.v1.subnetwork 17 | properties: 18 | ipCidrRange: 10.0.2.0/24 19 | network: $(ref.antmedia-vpc-network.selfLink) 20 | region: {{ properties["region"] }} 21 | 22 | - name: firewall-rule 23 | type: compute.v1.firewall 24 | properties: 25 | network: $(ref.antmedia-vpc-network.selfLink) 26 | sourceRanges: 27 | - 0.0.0.0/0 28 | allowed: 29 | - IPProtocol: tcp 30 | ports: 31 | - "80" 32 | - "443" 33 | - "22" 34 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia.jinja: -------------------------------------------------------------------------------- 1 | {# 2 | Copyright 2016 Google Inc. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | #} 15 | 16 | {% set default_zone = "us-central1-a" %} 17 | {% set default_region = "us-central1" %} 18 | {% set mongodb_machine_type = "e2-standard-2" %} 19 | {% set origin_machine_type = "c2d-standard-4" %} 20 | {% set edge_machine_type = "c2d-standard-4" %} 21 | {% set image_id = "ams-latest" %} 22 | 23 | 24 | 25 | resources: 26 | - name: antmedia-mongodb 27 | type: antmedia-mongodb-template.jinja 28 | properties: 29 | zone: {{ default_zone }} 30 | machine_type: {{ mongodb_machine_type }} 31 | - name: antmedia-instance 32 | type: antmedia-instance-template.jinja 33 | properties: 34 | zone: {{ default_zone }} 35 | origin_machine_type: {{ origin_machine_type }} 36 | edge_machine_type: {{ edge_machine_type }} 37 | image_id: {{ image_id }} 38 | 39 | - name: antmedia-instance-group 40 | type: antmedia-instance-group-template.jinja 41 | properties: 42 | zone: {{ default_zone }} 43 | - name: antmedia-loadbalancer 44 | type: antmedia-loadbalancer-template.jinja 45 | properties: 46 | zone: {{ default_zone }} 47 | region: {{ default_region}} 48 | - name: antmedia-firewall 49 | type: antmedia-firewall-template.jinja 50 | properties: 51 | zone: {{ default_zone}} 52 | - name: antmedia-vpc-network 53 | type: antmedia-vpc-template.jinja 54 | properties: 55 | region: {{ default_region}} 56 | autoCreateSubnetworks: false 57 | 58 | -------------------------------------------------------------------------------- /gcp-jinja-template/antmedia.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | imports: 16 | - path: antmedia-vpc-template.jinja 17 | - path: antmedia-mongodb-template.jinja 18 | - path: antmedia-instance-template.jinja 19 | - path: antmedia-instance-group-template.jinja 20 | - path: antmedia-firewall-template.jinja 21 | - path: antmedia-loadbalancer-template.jinja 22 | - path: antmedia.jinja 23 | 24 | resources: 25 | - name: antmedia 26 | type: antmedia.jinja 27 | -------------------------------------------------------------------------------- /gcp-jinja-template/backend.jinja: -------------------------------------------------------------------------------- 1 | --- 2 | # Your resource definitions go here under resources key 3 | resources: 4 | - name: my-backend-service # Replace with your desired name 5 | type: compute.v1.backendService # Adjust type based on resource 6 | properties: 7 | portName: http 8 | protocol: HTTP 9 | backend: 10 | group: origin-instance-group # Assuming your instance group name 11 | healthChecks: 12 | - https://www.googleapis.com/compute/v1/healthChecks/default 13 | 14 | # You can add other outputs here if needed 15 | output: 16 | # ... 17 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script creates user for standalone aws server and cloudformation template. 4 | # 5 | INITIALIZED=/usr/local/antmedia/conf/initialized 6 | if [ ! -f "$INITIALIZED" ] 7 | then 8 | TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 9 | ## Local IPV4 10 | 11 | export LOCAL_IPv4=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4` 12 | 13 | # $HOSTNAME ip-172-30-0-216 14 | HOST_NAME=`hostname` 15 | 16 | HOST_LINE="$LOCAL_IPv4 $HOST_NAME" 17 | grep -Fxq "$HOST_LINE" /etc/hosts 18 | 19 | OUT=$? 20 | if [ $OUT -ne 0 ]; then 21 | 22 | echo "$HOST_LINE" | tee -a /etc/hosts 23 | OUT=$? 24 | 25 | if [ $OUT -ne 0 ]; then 26 | echo "Cannot write hosts file" 27 | exit $OUT 28 | fi 29 | fi 30 | ## Instance ID 31 | export INSTANCE_ID=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id` 32 | 33 | #check if first login 34 | 35 | RESULT=`curl -s -X GET -H "Content-Type: application/json" http://localhost:5080/rest/v2/first-login-status` 36 | echo ${RESULT} | grep --quiet ":false" 37 | 38 | #if the above commands returns 0, it means server is already initialized 39 | if [ $? = 0 ]; then 40 | echo "First login is not true" 41 | touch $INITIALIZED 42 | exit 0 43 | else 44 | ## Add Initial User with curl 45 | RESULT=`curl -s -X POST -H "Content-Type: application/json" -d '{"email": "JamesBond", "password": "'$INSTANCE_ID'", "scope": "system", "userType": "ADMIN"}' http://localhost:5080/rest/v2/users/initial` 46 | 47 | echo ${RESULT} | grep --quiet ":true" 48 | 49 | if [ ! $1 ]; then 50 | echo ${RESULT} | grep --quiet ":true" 51 | if [ $? = 1 ]; then 52 | echo "Cannot create initial user" 53 | echo "sleep 3 ; /usr/local/antmedia/conf/init.sh" | at now 54 | exit $OUT 55 | else 56 | echo ${RESULT} | grep --quiet ":true" 57 | fi 58 | 59 | fi 60 | touch $INITIALIZED 61 | 62 | fi 63 | 64 | fi -------------------------------------------------------------------------------- /install-monitoring-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Usage 5 | # sudo ./install-monitoring-tools.sh [-y] [-m MEMORY] 6 | # -y provides headless installation and accepts that server is not behind NAT 7 | # -m MEMORY specifies the memory of the ElasticSearch because ElasticSearch may not be started with default value. 8 | # You can give -m 2g , -m 2048m as memory limit 9 | # 10 | 11 | PUBLIC_IP=$(curl -s http://checkip.amazonaws.com) 12 | RED='\033[0;31m' 13 | NC='\033[0m' 14 | 15 | HEADLESS_INSTALL=false 16 | ELASTIC_SEARCH_MEMORY= 17 | 18 | check() { 19 | OUT=$? 20 | if [ $OUT -ne 0 ]; then 21 | #sudo journalctl -xe 22 | echo "There is a problem in installing the monitoring tools. Please take a look at the logs above to understand the problem. If you need help, please send the log of this console to support@antmedia.io" 23 | exit $OUT 24 | fi 25 | } 26 | 27 | distro () { 28 | os_release="/etc/os-release" 29 | if [ -f "$os_release" ]; then 30 | . $os_release 31 | msg="We are supporting Ubuntu 18.04, Ubuntu 20.04, Ubuntu 20.10" 32 | 33 | elif [ "$ID" == "ubuntu" ] || [ "$ID" == "centos" ]; then 34 | if [ "$VERSION_ID" != "18.04" ] && [ "$VERSION_ID" != "20.04" ] && [ "$VERSION_ID" != "20.10" ]; then 35 | echo $msg 36 | exit 1 37 | fi 38 | else 39 | echo $msg 40 | exit 1 41 | fi 42 | } 43 | 44 | check_network () { 45 | 46 | if [ "$HEADLESS_INSTALL" == "false" ]; then 47 | echo -e "Are you using the monitoring tool behind the NAT network? [Y/n]" 48 | read nat 49 | nat=${nat^} 50 | if [ "$nat" == "Y" ]; then 51 | read -p "Please enter your private IP: " private_ip 52 | PRIVATE_IP=$private_ip 53 | if [ -z $PRIVATE_IP ]; then 54 | echo "Private IP cannot be empty." 55 | exit 1 56 | fi 57 | else 58 | PRIVATE_IP="127.0.0.1" 59 | fi 60 | else 61 | #default value is not installing behind NAT 62 | PRIVATE_IP="127.0.0.1" 63 | fi 64 | } 65 | 66 | check_ip() { 67 | if [[ $PRIVATE_IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 68 | echo "" 69 | else 70 | echo -e "\e[41mPlease enter valid IP address.${NC}" 71 | check_network 72 | fi 73 | } 74 | 75 | # y means headless installation 76 | while getopts 'ym:' option 77 | do 78 | case "${option}" in 79 | y) HEADLESS_INSTALL=true ;; 80 | m) ELASTIC_SEARCH_MEMORY=${OPTARG} ;; 81 | esac 82 | done 83 | 84 | distro 85 | check_network 86 | check_ip 87 | 88 | install () { 89 | sudo apt-get update -qq 2> /dev/null 90 | check 91 | sudo apt-get install apt-transport-https software-properties-common wget -y -qq 92 | check 93 | sudo rm -rf /opt/kafka* 94 | check 95 | wget -qO- https://raw.githubusercontent.com/ant-media/Scripts/master/cloudformation/kafka_2.13-2.8.1.tgz | tar -zxvf - -C /opt/ && mv /opt/kafka* /opt/kafka 96 | check 97 | wget -qO- https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - 98 | check 99 | 100 | echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list 101 | check 102 | sudo wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key 103 | 104 | check 105 | echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list 106 | check 107 | 108 | sudo apt-get update -qq 2> /dev/null 109 | check 110 | sudo apt-get install openjdk-11-jdk -y -qq 111 | check 112 | sudo apt-get install elasticsearch logstash grafana -y -qq 113 | 114 | check 115 | 116 | CPU=$(grep -c 'processor' /proc/cpuinfo) 117 | check 118 | 119 | MEMORY=$(awk '/MemTotal/ {print int($2/1024/1024)}' /proc/meminfo) 120 | check 121 | 122 | DASHBOARD_URL="https://raw.githubusercontent.com/ant-media/Scripts/master/monitor/antmediaserver.json" 123 | DATASOURCE_URL="https://raw.githubusercontent.com/ant-media/Scripts/master/monitor/datasource.json" 124 | 125 | if [ "$MEMORY" -ge "7" ]; then 126 | sudo sed -i -e 's/-Xms1g/-Xms4g/g' -e 's/-Xmx1g/-Xmx4g/g' /etc/logstash/jvm.options 127 | fi 128 | 129 | sudo sed -i "s/#.*pipeline.workers: 2/pipeline.workers: $CPU/g" /etc/logstash/logstash.yml 130 | check 131 | 132 | sudo sed -i 's/num.partitions=1/num.partitions=4/g' /opt/kafka/config/server.properties 133 | check 134 | 135 | sudo cat < /lib/systemd/system/kafka.service 136 | 137 | [Unit] 138 | Description=Apache Kafka Server 139 | Requires=network.target remote-fs.target 140 | After=network.target remote-fs.target kafka-zookeeper.service 141 | 142 | [Service] 143 | Type=simple 144 | Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 145 | ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties 146 | ExecStop=/opt/kafka/bin/kafka-server-stop.sh 147 | 148 | [Install] 149 | WantedBy=multi-user.target 150 | 151 | EOF 152 | 153 | sudo cat << EOF > /lib/systemd/system/kafka-zookeeper.service 154 | 155 | [Unit] 156 | Description=Apache Zookeeper Server 157 | Requires=network.target remote-fs.target 158 | After=network.target remote-fs.target 159 | 160 | [Service] 161 | Type=simple 162 | Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 163 | ExecStart=/opt/kafka/bin/zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties 164 | ExecStop=/opt/kafka/bin/zookeeper-server-stop.sh 165 | 166 | [Install] 167 | WantedBy=multi-user.target 168 | EOF 169 | 170 | sudo cat < /etc/logstash/conf.d/logstash.conf 171 | input { 172 | kafka { 173 | bootstrap_servers => "127.0.0.1:9092" 174 | client_id => "logstash" 175 | group_id => "logstash" 176 | consumer_threads => 4 177 | topics => ["ams-instance-stats","ams-webrtc-stats","kafka-webrtc-tester-stats"] 178 | codec => "json" 179 | tags => ["log", "kafka_source"] 180 | type => "log" 181 | } 182 | } 183 | 184 | output { 185 | elasticsearch { 186 | hosts => ["127.0.0.1:9200"] 187 | index => "logstash-%{[type]}-%{+YYYY.MM.dd}" 188 | } 189 | } 190 | EOF 191 | 192 | sudo cat <> /opt/kafka/config/server.properties 193 | advertised.listeners=INTERNAL_PLAINTEXT://$PRIVATE_IP:9093,EXTERNAL_PLAINTEXT://$PUBLIC_IP:9092 194 | listeners=INTERNAL_PLAINTEXT://0.0.0.0:9093,EXTERNAL_PLAINTEXT://0.0.0.0:9092 195 | inter.broker.listener.name=INTERNAL_PLAINTEXT 196 | listener.security.protocol.map=INTERNAL_PLAINTEXT:PLAINTEXT,EXTERNAL_PLAINTEXT:PLAINTEXT 197 | EOF 198 | 199 | 200 | sudo systemctl daemon-reload 201 | check 202 | 203 | sudo systemctl enable grafana-server 204 | check 205 | 206 | sudo systemctl restart grafana-server 207 | check 208 | 209 | if [ ! -z $ELASTIC_SEARCH_MEMORY ]; then 210 | 211 | sudo sed -i "/.*-Xmx.*/c\-Xmx${ELASTIC_SEARCH_MEMORY}" /etc/elasticsearch/jvm.options 212 | sudo sed -i "/.*-Xms.*/c\-Xms${ELASTIC_SEARCH_MEMORY}" /etc/elasticsearch/jvm.options 213 | 214 | fi 215 | 216 | 217 | echo "Enabling Logstash" 218 | sudo systemctl enable logstash.service 219 | check 220 | 221 | echo "Enabling Elasticsearch" 222 | sudo systemctl enable elasticsearch 223 | check 224 | 225 | echo "Enabling Kafka" 226 | sudo systemctl enable kafka 227 | check 228 | 229 | echo "Enabling Kafka-zookeeper" 230 | sudo systemctl enable kafka-zookeeper 231 | check 232 | 233 | echo "Starting kafka-zookeeper" 234 | sudo systemctl restart kafka-zookeeper 235 | check 236 | 237 | echo "Starting Kafka" 238 | sudo systemctl restart kafka 239 | check 240 | 241 | echo "Starting Elasticsearch" 242 | sudo systemctl restart elasticsearch 243 | OUT=$? 244 | if [ $OUT -ne 0 ]; then 245 | echo "Elastic search is not started. The problem may be about memory limit. You can give memory limit with -m option. Such as -m 4g, -m 1g . If that does not help, please send the log of this console to support@antmedia.io" 246 | exit $OUT 247 | fi 248 | 249 | echo "Starting Logstash" 250 | sudo systemctl restart logstash 251 | check 252 | 253 | 254 | # We create this panel creation here because we need some time to make grafana get started 255 | wget -q $DASHBOARD_URL -O /tmp/antmediaserver.json 256 | check 257 | wget -q $DATASOURCE_URL -O /tmp/antmedia-datasource.json 258 | check 259 | 260 | echo "Creating Ant Media Server Grafana Panel" 261 | sudo curl -s "http://127.0.0.1:3000/api/dashboards/db" \ 262 | -u "admin:admin" \ 263 | -H "Content-Type: application/json" \ 264 | --data-binary "@/tmp/antmediaserver.json" 265 | 266 | check 267 | 268 | echo "Creating Elastich Search DataSource for Ant Media Server Grafana Panel" 269 | sudo curl -s -X "POST" "http://127.0.0.1:3000/api/datasources" \ 270 | -H "Content-Type: application/json" \ 271 | -u "admin:admin" \ 272 | --data-binary "@/tmp/antmedia-datasource.json" 273 | 274 | check 275 | } 276 | echo "Installing Ant Media Server Monitor Tools" 277 | 278 | install 279 | 280 | echo "Monitor Tools Installed succesfully..." 281 | 282 | echo -e "\n" 283 | echo -e "Login URL: ${RED}http://$PUBLIC_IP:3000${NC}" 284 | echo -e "Username and Password: ${RED}admin/admin${NC}\n" 285 | 286 | -------------------------------------------------------------------------------- /install_graylog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PUBLIC_IP="$(curl -s http://checkip.amazonaws.com)" 4 | 5 | sudo apt-get update 6 | sudo apt-get install apt-transport-https openjdk-11-jre openjdk-11-jre-headless uuid-runtime pwgen gnupg -y 7 | 8 | wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - 9 | echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu `lsb_release -cs`/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list 10 | sudo apt-get update && sudo apt-get install -y mongodb-org -y 11 | sudo systemctl restart mongod 12 | 13 | wget -O - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add 14 | echo "deb https://artifacts.elastic.co/packages/oss-7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list 15 | sudo apt-get update && sudo apt-get install elasticsearch-oss -y 16 | 17 | sudo tee -a /etc/elasticsearch/elasticsearch.yml > /dev/null < /tmp/mongo_credentials.txt 61 | echo "MongoDB password: $password" >> /tmp/mongo_credentials.txt 62 | 63 | echo "MongoDB credentials saved to /tmp/mongo_credentials.txt" 64 | else 65 | # Start MongoDB without authentication 66 | sudo sed -i 's/bindIp:.*/bindIp: 0.0.0.0/g' /etc/mongod.conf 67 | sudo systemctl restart mongod 68 | sudo systemctl enable mongod 69 | 70 | echo "MongoDB installed without username and password" 71 | fi 72 | -------------------------------------------------------------------------------- /install_turn-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if user is running as root 4 | if [[ $EUID -ne 0 ]]; then 5 | echo "This script must be run as root." 6 | exit 1 7 | fi 8 | 9 | # Function to install Coturn 10 | install_coturn() { 11 | apt-get update 12 | apt-get install -y coturn 13 | truncate -s 0 /etc/turnserver.conf 14 | } 15 | 16 | # Function to generate random username 17 | generate_credentials() { 18 | username=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 8 | head -n 1) 19 | password=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 1) 20 | echo "Username: $username" 21 | echo "Password: $password" 22 | echo "lt-cred-mech" >> /etc/turnserver.conf 23 | echo "user=$username:$password" >> /etc/turnserver.conf 24 | } 25 | 26 | # Function to configure Coturn for NAT network 27 | configure_nat() { 28 | # Add necessary configuration options for NAT network 29 | echo 'TURNSERVER_ENABLED=1' >> /etc/default/coturn 30 | # Get public IP 31 | public_ip=$(curl -s http://checkip.amazonaws.com) 32 | 33 | # Get private IP 34 | private_ip=$(hostname -I | awk '{print $1}') 35 | 36 | # Add external IP configuration to turnserver.conf 37 | echo "external-ip=$public_ip/$private_ip" >> /etc/turnserver.conf 38 | echo "realm=$public_ip" >> /etc/turnserver.conf 39 | } 40 | 41 | # Function to configure Coturn for public IP 42 | configure_public_ip() { 43 | # Add necessary configuration options for public IP 44 | echo 'TURNSERVER_ENABLED=1' >> /etc/default/coturn 45 | 46 | # Get public IP 47 | public_ip=$(curl -s http://checkip.amazonaws.com) 48 | 49 | # Add external IP configuration to turnserver.conf 50 | echo "realm=$public_ip" >> /etc/turnserver.conf 51 | } 52 | 53 | # Main script 54 | 55 | # Prompt user for configuration option 56 | echo "Choose the configuration option:" 57 | echo "1. Behind NAT network (e.g., AWS)" 58 | echo "2. Directly accessible public IP" 59 | read -r -p "Enter your choice (1 or 2): " option 60 | 61 | case $option in 62 | 1) 63 | install_coturn 64 | generate_credentials 65 | configure_nat 66 | ;; 67 | 2) 68 | install_coturn 69 | generate_credentials 70 | configure_public_ip 71 | ;; 72 | *) 73 | echo "Invalid choice. Exiting." 74 | exit 1 75 | ;; 76 | esac 77 | 78 | # Start and enable Coturn service 79 | systemctl restart coturn 80 | systemctl enable coturn 81 | 82 | echo "Coturn installation and configuration completed." 83 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-deployment-edge.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-server-edge 5 | spec: 6 | selector: 7 | app: ant-media-edge 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 5080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: ant-media-server-edge 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: ant-media-edge 21 | replicas: 1 22 | template: 23 | metadata: 24 | labels: 25 | app: ant-media-edge 26 | spec: 27 | affinity: 28 | podAntiAffinity: 29 | requiredDuringSchedulingIgnoredDuringExecution: 30 | - labelSelector: 31 | matchExpressions: 32 | - key: app 33 | operator: In 34 | values: 35 | - ant-media-edge 36 | - ant-media-origin 37 | topologyKey: "kubernetes.io/hostname" 38 | hostNetwork: true 39 | dnsPolicy: ClusterFirstWithHostNet 40 | containers: 41 | - name: ant-media-server 42 | imagePullPolicy: IfNotPresent # change this value accordingly. It can be Never, Always or IfNotPresent 43 | image: antmedia/enterprise:latest #change this value according to your image. 44 | # By default, mongodb deployment is used. If you're using mongodb somewhere else, specify it with server url(-h) below. 45 | # You may also need to add -u and -p parameters for 46 | # specifying mongodb username and passwords respectively 47 | args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] 48 | env: 49 | - name: POD_NAME 50 | valueFrom: 51 | fieldRef: 52 | apiVersion: v1 53 | fieldPath: metadata.name 54 | volumeMounts: 55 | - mountPath: /tmp 56 | name: temp-volume 57 | - mountPath: /var/log/antmedia/ 58 | name: log-storage 59 | subPath: $(POD_NAME) 60 | lifecycle: 61 | postStart: 62 | exec: 63 | command: 64 | - /bin/sh 65 | - -c 66 | - chmod 1777 /tmp 67 | livenessProbe: 68 | httpGet: 69 | path: / 70 | port: 5080 71 | initialDelaySeconds: 30 72 | periodSeconds: 10 73 | readinessProbe: 74 | httpGet: 75 | path: / 76 | port: 5080 77 | initialDelaySeconds: 30 78 | periodSeconds: 10 79 | resources: 80 | requests: 81 | cpu: 4000m 82 | volumes: 83 | - hostPath: 84 | path: /temp-data 85 | type: DirectoryOrCreate 86 | name: temp-volume 87 | - hostPath: 88 | path: /mnt/logs/antmedia 89 | type: DirectoryOrCreate 90 | name: log-storage 91 | 92 | # imagePullSecrets: 93 | # - name: docker 94 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-deployment-origin.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-server-origin 5 | spec: 6 | selector: 7 | app: ant-media-origin 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 5080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: ant-media-server-origin 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: ant-media-origin 21 | replicas: 1 22 | template: 23 | metadata: 24 | labels: 25 | app: ant-media-origin 26 | spec: 27 | affinity: 28 | podAntiAffinity: 29 | requiredDuringSchedulingIgnoredDuringExecution: 30 | - labelSelector: 31 | matchExpressions: 32 | - key: app 33 | operator: In 34 | values: 35 | - ant-media-edge 36 | - ant-media-origin 37 | topologyKey: "kubernetes.io/hostname" 38 | hostNetwork: true 39 | dnsPolicy: ClusterFirstWithHostNet 40 | containers: 41 | - name: ant-media-server 42 | imagePullPolicy: IfNotPresent # change this value accordingly. It can be Never, Always or IfNotPresent 43 | image: antmedia/enterprise:latest #change this value according to your image. 44 | # By default, mongodb deployment is used. If you're using mongodb somewhere else, specify it with server url(-h) below. 45 | # You may also need to add -u and -p parameters for 46 | # specifying mongodb username and passwords respectively 47 | args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] 48 | env: 49 | - name: POD_NAME 50 | valueFrom: 51 | fieldRef: 52 | apiVersion: v1 53 | fieldPath: metadata.name 54 | volumeMounts: 55 | - mountPath: /tmp 56 | name: temp-volume 57 | - mountPath: /var/log/antmedia/ 58 | name: log-storage 59 | subPath: $(POD_NAME) 60 | lifecycle: 61 | postStart: 62 | exec: 63 | command: 64 | - /bin/sh 65 | - -c 66 | - chmod 1777 /tmp 67 | livenessProbe: 68 | httpGet: 69 | path: / 70 | port: 5080 71 | initialDelaySeconds: 30 72 | periodSeconds: 10 73 | readinessProbe: 74 | httpGet: 75 | path: / 76 | port: 5080 77 | initialDelaySeconds: 30 78 | periodSeconds: 10 79 | resources: 80 | requests: 81 | cpu: 4000m 82 | volumes: 83 | - hostPath: 84 | path: /temp-data 85 | type: DirectoryOrCreate 86 | name: temp-volume 87 | - hostPath: 88 | path: /mnt/logs/antmedia 89 | type: DirectoryOrCreate 90 | name: log-storage 91 | # imagePullSecrets: 92 | # - name: docker 93 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-deployment.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-server 5 | spec: 6 | selector: 7 | app: ant-media 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 5080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: ant-media-server 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: ant-media 21 | replicas: 1 22 | template: 23 | metadata: 24 | labels: 25 | app: ant-media 26 | spec: 27 | affinity: 28 | podAntiAffinity: 29 | requiredDuringSchedulingIgnoredDuringExecution: 30 | - labelSelector: 31 | matchExpressions: 32 | - key: app 33 | operator: In 34 | values: 35 | - ant-media 36 | topologyKey: "kubernetes.io/hostname" 37 | hostNetwork: true 38 | dnsPolicy: ClusterFirstWithHostNet 39 | containers: 40 | - name: ant-media-server 41 | imagePullPolicy: IfNotPresent # change this value accordingly. It can be Never, Always or IfNotPresent 42 | image: ant-media-server-enterprise-k8s:test #change this value according to your image. 43 | # By default, mongodb deployment is used. If you're using mongodb somewhere else, specify it with server url(-h) below. 44 | # You may also need to add -u and -p parameters for 45 | # specifying mongodb username and passwords respectively 46 | args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] 47 | resources: 48 | requests: 49 | cpu: 1000m 50 | # imagePullSecrets: 51 | # - name: docker 52 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-hpa-edge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: ant-media-server-edge 5 | spec: 6 | scaleTargetRef: 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | name: ant-media-server-edge 10 | minReplicas: 1 11 | maxReplicas: 10 12 | targetCPUUtilizationPercentage: 60 13 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-hpa-origin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: ant-media-server-origin 5 | spec: 6 | scaleTargetRef: 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | name: ant-media-server-origin 10 | minReplicas: 1 11 | maxReplicas: 10 12 | targetCPUUtilizationPercentage: 60 13 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-hpa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: ant-media-server 5 | spec: 6 | scaleTargetRef: 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | name: ant-media-server 10 | minReplicas: 1 11 | maxReplicas: 10 12 | targetCPUUtilizationPercentage: 60 13 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-ingress-edge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ant-media-server-edge 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/affinity: "cookie" 8 | nginx.ingress.kubernetes.io/session-cookie-name: "route" 9 | nginx.ingress.kubernetes.io/session-cookie-expires: "172800" 10 | nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" 11 | nginx.org/websocket-services: "ant-media-server" 12 | nginx.ingress.kubernetes.io/websocket-services : "ant-media-server" 13 | nginx.ingress.kubernetes.io/proxy-body-size: "0m" 14 | spec: 15 | rules: 16 | - host: test.antmedia.cloud 17 | http: 18 | paths: 19 | - path: / 20 | pathType: Prefix 21 | backend: 22 | service: 23 | name: ant-media-server-edge 24 | port: 25 | number: 5080 26 | 27 | tls: 28 | - secretName: antmedia-cert-edge 29 | hosts: 30 | - test.antmedia.cloud 31 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-ingress-origin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ant-media-server-origin 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/affinity: "cookie" 8 | nginx.ingress.kubernetes.io/session-cookie-name: "route" 9 | nginx.ingress.kubernetes.io/session-cookie-expires: "172800" 10 | nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" 11 | nginx.org/websocket-services: "ant-media-server" 12 | nginx.ingress.kubernetes.io/websocket-services : "ant-media-server" 13 | nginx.ingress.kubernetes.io/proxy-body-size: "0m" 14 | spec: 15 | rules: 16 | - host: test.antmedia.cloud 17 | http: 18 | paths: 19 | - path: / 20 | pathType: Prefix 21 | backend: 22 | service: 23 | name: ant-media-server-origin 24 | port: 25 | number: 5080 26 | 27 | tls: 28 | - secretName: antmedia-cert-origin 29 | hosts: 30 | - test.antmedia.cloud 31 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ant-media-server 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/affinity: "cookie" 8 | nginx.ingress.kubernetes.io/session-cookie-name: "route" 9 | nginx.ingress.kubernetes.io/session-cookie-expires: "172800" 10 | nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" 11 | nginx.org/websocket-services: "ant-media-server" 12 | nginx.ingress.kubernetes.io/websocket-services : "ant-media-server" 13 | spec: 14 | rules: 15 | - host: test.antmedia.cloud 16 | http: 17 | paths: 18 | - path: / 19 | pathType: Prefix 20 | backend: 21 | service: 22 | name: ant-media-server 23 | port: 24 | number: 5080 25 | 26 | tls: 27 | - secretName: antmedia-cert 28 | hosts: 29 | - test.antmedia.cloud 30 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-issuer-production.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-production 5 | spec: 6 | acme: 7 | server: https://acme-v02.api.letsencrypt.org/directory 8 | email: change@me 9 | privateKeySecretRef: 10 | name: letsencrypt-production 11 | solvers: 12 | - http01: 13 | ingress: 14 | class: nginx 15 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-issuer-staging.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-staging 5 | spec: 6 | acme: 7 | server: https://acme-staging-v02.api.letsencrypt.org/directory 8 | email: change@me 9 | privateKeySecretRef: 10 | name: letsencrypt-staging 11 | solvers: 12 | - http01: 13 | ingress: 14 | class: nginx 15 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-mongodb.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: mongo 5 | spec: 6 | selector: 7 | app: mongo 8 | ports: 9 | - protocol: TCP 10 | port: 27017 11 | --- 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: mongo 16 | spec: 17 | selector: 18 | matchLabels: 19 | app: mongo 20 | replicas: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: mongo 25 | spec: 26 | containers: 27 | - name: mongodb 28 | imagePullPolicy: Always 29 | image: mongo:6.0 30 | ports: 31 | - containerPort: 27017 32 | 33 | -------------------------------------------------------------------------------- /kubernetes/ams-k8s-rtmp.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-rtmp 5 | spec: 6 | type: LoadBalancer 7 | externalTrafficPolicy: Cluster 8 | ports: 9 | - name: rtmp 10 | port: 1935 11 | targetPort: 1935 12 | protocol: TCP 13 | selector: 14 | app: ant-media-origin -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-coturn.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | namespace: default 5 | name: coturn 6 | labels: 7 | app.kubernetes.io/name: coturn 8 | app.kubernetes.io/instance: coturn 9 | app.kubernetes.io/version: 0.0.1 10 | spec: 11 | # replicas: 1 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: coturn 15 | app.kubernetes.io/instance: coturn 16 | app.kubernetes.io/version: 0.0.1 17 | template: 18 | metadata: 19 | labels: 20 | app.kubernetes.io/name: coturn 21 | app.kubernetes.io/instance: coturn 22 | app.kubernetes.io/version: 0.0.1 23 | spec: 24 | hostNetwork: true 25 | containers: 26 | - name: coturn 27 | image: coturn/coturn 28 | imagePullPolicy: Always 29 | env: 30 | - name: MY_POD_IP 31 | valueFrom: 32 | fieldRef: 33 | fieldPath: status.podIP 34 | ports: 35 | - name: turn-port1 36 | containerPort: 3478 37 | hostPort: 3478 38 | protocol: UDP 39 | - name: turn-port2 40 | containerPort: 3478 41 | hostPort: 3478 42 | protocol: TCP 43 | args: 44 | - "-a" 45 | - "-f" 46 | - "--user=username:password" 47 | - "-p" 48 | - "3478" 49 | - "-v" 50 | - "--external-ip=$(detect-external-ip)/$MY_POD_IP" 51 | - "--realm=$(detect-external-ip)" 52 | 53 | --- 54 | 55 | apiVersion: v1 56 | kind: Service 57 | metadata: 58 | name: coturn 59 | namespace: default 60 | labels: 61 | app.kubernetes.io/name: coturn 62 | app.kubernetes.io/instance: coturn 63 | app.kubernetes.io/version: 0.0.1 64 | spec: 65 | type: ClusterIP 66 | ports: 67 | - port: 3478 68 | targetPort: 3478 69 | protocol: UDP 70 | name: turn-port1 71 | - port: 3478 72 | targetPort: 3478 73 | protocol: TCP 74 | name: turn-port2 75 | 76 | selector: 77 | app.kubernetes.io/name: coturn 78 | app.kubernetes.io/instance: coturn 79 | app.kubernetes.io/version: 0.0.1 -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-deployment-edge.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-server-edge 5 | spec: 6 | selector: 7 | app: ant-media-edge 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 5080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: ant-media-server-edge 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: ant-media-edge 21 | replicas: 3 22 | template: 23 | metadata: 24 | labels: 25 | app: ant-media-edge 26 | spec: 27 | dnsPolicy: ClusterFirstWithHostNet 28 | containers: 29 | - name: ant-media-server 30 | imagePullPolicy: IfNotPresent # change this value accordingly. It can be Never, Always or IfNotPresent 31 | image: antmedia/enterprise:latest #change this value according to your image. 32 | # By default, mongodb deployment is used. If you're using mongodb somewhere else, specify it with server url(-h) below. 33 | # You may also need to add -u and -p parameters for 34 | # specifying mongodb username and passwords respectively 35 | # args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] 36 | args: ["-r", "true", "-m", "cluster", "-h", "mongo"] 37 | env: 38 | - name: POD_NAME 39 | valueFrom: 40 | fieldRef: 41 | apiVersion: v1 42 | fieldPath: metadata.name 43 | volumeMounts: 44 | - mountPath: /tmp 45 | name: temp-volume 46 | - mountPath: /var/log/antmedia/ 47 | name: log-storage 48 | subPath: $(POD_NAME) 49 | lifecycle: 50 | postStart: 51 | exec: 52 | command: 53 | - /bin/sh 54 | - -c 55 | - chmod 1777 /tmp 56 | livenessProbe: 57 | httpGet: 58 | path: / 59 | port: 5080 60 | initialDelaySeconds: 30 61 | periodSeconds: 10 62 | readinessProbe: 63 | httpGet: 64 | path: / 65 | port: 5080 66 | initialDelaySeconds: 30 67 | periodSeconds: 10 68 | resources: 69 | requests: 70 | cpu: 4000m 71 | volumes: 72 | - hostPath: 73 | path: /temp-data 74 | type: DirectoryOrCreate 75 | name: temp-volume 76 | - hostPath: 77 | path: /mnt/logs/antmedia 78 | type: DirectoryOrCreate 79 | name: log-storage 80 | 81 | # imagePullSecrets: 82 | # - name: docker -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-deployment-origin.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-server-origin 5 | spec: 6 | selector: 7 | app: ant-media-origin 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: 5080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: ant-media-server-origin 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: ant-media-origin 21 | replicas: 3 22 | template: 23 | metadata: 24 | labels: 25 | app: ant-media-origin 26 | spec: 27 | dnsPolicy: ClusterFirstWithHostNet 28 | containers: 29 | - name: ant-media-server 30 | imagePullPolicy: IfNotPresent # change this value accordingly. It can be Never, Always or IfNotPresent 31 | image: antmedia/enterprise:latest #change this value according to your image. 32 | # By default, mongodb deployment is used. If you're using mongodb somewhere else, specify it with server url(-h) below. 33 | # You may also need to add -u and -p parameters for 34 | # specifying mongodb username and passwords respectively 35 | # args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] 36 | args: ["-r", "true", "-m", "cluster", "-h", "mongo"] 37 | env: 38 | - name: POD_NAME 39 | valueFrom: 40 | fieldRef: 41 | apiVersion: v1 42 | fieldPath: metadata.name 43 | volumeMounts: 44 | - mountPath: /tmp 45 | name: temp-volume 46 | - mountPath: /var/log/antmedia/ 47 | name: log-storage 48 | subPath: $(POD_NAME) 49 | lifecycle: 50 | postStart: 51 | exec: 52 | command: 53 | - /bin/sh 54 | - -c 55 | - chmod 1777 /tmp 56 | livenessProbe: 57 | httpGet: 58 | path: / 59 | port: 5080 60 | initialDelaySeconds: 30 61 | periodSeconds: 10 62 | readinessProbe: 63 | httpGet: 64 | path: / 65 | port: 5080 66 | initialDelaySeconds: 30 67 | periodSeconds: 10 68 | resources: 69 | requests: 70 | cpu: 4000m 71 | volumes: 72 | - hostPath: 73 | path: /temp-data 74 | type: DirectoryOrCreate 75 | name: temp-volume 76 | - hostPath: 77 | path: /mnt/logs/antmedia 78 | type: DirectoryOrCreate 79 | name: log-storage 80 | 81 | # imagePullSecrets: 82 | # - name: docker -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-hpa-edge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: ant-media-server-edge 5 | spec: 6 | scaleTargetRef: 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | name: ant-media-server-edge 10 | minReplicas: 5 11 | maxReplicas: 10 12 | targetCPUUtilizationPercentage: 60 13 | -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-hpa-origin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: ant-media-server-origin 5 | spec: 6 | scaleTargetRef: 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | name: ant-media-server-origin 10 | minReplicas: 1 11 | maxReplicas: 10 12 | targetCPUUtilizationPercentage: 60 13 | -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-ingress-edge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ant-media-server-edge 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/affinity: "cookie" 8 | nginx.ingress.kubernetes.io/session-cookie-name: "route" 9 | nginx.ingress.kubernetes.io/session-cookie-expires: "172800" 10 | nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" 11 | nginx.ingress.kubernetes.io/proxy-body-size: "0m" 12 | spec: 13 | rules: 14 | - host: edge.antmedia.cloud 15 | http: 16 | paths: 17 | - path: / 18 | pathType: Prefix 19 | backend: 20 | service: 21 | name: ant-media-server-edge 22 | port: 23 | number: 5080 24 | 25 | tls: 26 | - secretName: antmedia-cert 27 | hosts: 28 | - edge.antmedia.cloud 29 | -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-ingress-origin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ant-media-server-origin 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/affinity: "cookie" 8 | nginx.ingress.kubernetes.io/session-cookie-name: "route" 9 | nginx.ingress.kubernetes.io/session-cookie-expires: "172800" 10 | nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" 11 | nginx.ingress.kubernetes.io/proxy-body-size: "0m" 12 | spec: 13 | rules: 14 | - host: origin.antmedia.cloud 15 | http: 16 | paths: 17 | - path: / 18 | pathType: Prefix 19 | backend: 20 | service: 21 | name: ant-media-server-origin 22 | port: 23 | number: 5080 24 | 25 | tls: 26 | - secretName: antmedia-cert 27 | hosts: 28 | - origin.antmedia.cloud 29 | -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-mongodb.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: mongo 5 | spec: 6 | selector: 7 | app: mongo 8 | ports: 9 | - protocol: TCP 10 | port: 27017 11 | --- 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: mongo 16 | spec: 17 | selector: 18 | matchLabels: 19 | app: mongo 20 | replicas: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: mongo 25 | spec: 26 | containers: 27 | - name: mongodb 28 | imagePullPolicy: Always 29 | image: mongo:6.0 30 | ports: 31 | - containerPort: 27017 32 | 33 | -------------------------------------------------------------------------------- /kubernetes/ams-with-turn-server/ams-k8s-rtmp.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ant-media-rtmp 5 | spec: 6 | type: LoadBalancer 7 | externalTrafficPolicy: Cluster 8 | ports: 9 | - name: rtmp 10 | port: 1935 11 | targetPort: 1935 12 | protocol: TCP 13 | selector: 14 | app: ant-media-origin -------------------------------------------------------------------------------- /lambda_functions/enable_ssl_check_domains.py: -------------------------------------------------------------------------------- 1 | import boto3, re, requests, json 2 | 3 | HOSTED_ZONE_ID = 'Z3BEXQLL4B8OB1' 4 | DOMAIN = 'antmedia.cloud' 5 | ec2 = boto3.resource('ec2') 6 | route53 = boto3.client('route53') 7 | URL = ":5080/WebRTCAppEE/rest/v2/version" 8 | s3_client = boto3.client('s3') 9 | BUCKET_NAME = "antmedia-subdomain-check" 10 | LAMBDA_LOCAL_TMP_FILE = '/tmp/invalid_domains.txt' 11 | 12 | def lambda_handler(event, context): 13 | 14 | headers = { 15 | 'Content-Type': 'application/json', 16 | } 17 | 18 | res = route53.list_resource_record_sets( 19 | HostedZoneId=HOSTED_ZONE_ID, 20 | StartRecordName='ams-*', 21 | StartRecordType='A', 22 | MaxItems='5000', 23 | ) 24 | 25 | for resource in res['ResourceRecordSets']: 26 | name = re.findall('ams-([0-9]*)', resource['Name']) 27 | if name: 28 | subdomain_list = resource['Name'][:-1] 29 | try: 30 | response = requests.get("http://" + subdomain_list + URL, headers=headers, timeout=1) 31 | response.raise_for_status() 32 | if response.status_code == 200: 33 | print("valid", subdomain_list) 34 | except requests.exceptions.RequestException as err: 35 | print("invalid", subdomain_list) 36 | with open(LAMBDA_LOCAL_TMP_FILE, 'a') as f: 37 | f.write(subdomain_list + "\n") 38 | 39 | s3_client.upload_file(LAMBDA_LOCAL_TMP_FILE, 'antmedia-subdomain-check', 'invalid_domains.txt') 40 | return { 41 | 'statusCode': 200, 42 | 'body': json.dumps('success') 43 | } 44 | 45 | -------------------------------------------------------------------------------- /lambda_functions/enable_ssl_delete_domains.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | 3 | 4 | def lambda_handler(event, context): 5 | # Update the bucket name with your S3 bucket name 6 | bucket_name = 'antmedia-subdomain-check' 7 | 8 | file1_key = 'invalid_domains-1.txt' 9 | file2_key = 'invalid_domains-2.txt' 10 | output_key = 'invalid_domains.txt' 11 | 12 | # Get the file name from the event 13 | file_name = 'invalid_domains.txt' 14 | 15 | # Create an S3 client 16 | s3_client = boto3.client('s3') 17 | 18 | compare_files(bucket_name, file1_key, file2_key, output_key) 19 | 20 | try: 21 | # Download the file from S3 22 | response = s3_client.get_object(Bucket=bucket_name, Key=file_name) 23 | contents = response['Body'].read().decode('utf-8') 24 | 25 | # Extract invalid subdomains from the file contents 26 | invalid_subdomains = contents.split('\n') 27 | 28 | # Create a Route 53 client 29 | route53_client = boto3.client('route53') 30 | 31 | # Delete the Route 53 resource record sets for each invalid subdomain 32 | for subdomain in invalid_subdomains: 33 | domain_name = subdomain.strip() + '.' 34 | print (domain_name) 35 | 36 | # List the resource record sets in the hosted zone 37 | response = route53_client.list_resource_record_sets( 38 | HostedZoneId='Z3BEXQLL4B8OB1', 39 | StartRecordName=domain_name, 40 | StartRecordType='A', # Change to the appropriate record type 41 | MaxItems='1' 42 | ) 43 | 44 | record_sets = response['ResourceRecordSets'] 45 | 46 | # Verify that the subdomain exists in the hosted zone 47 | if len(record_sets) > 0 and record_sets[0]['Name'] == domain_name: 48 | # Delete the resource record set 49 | response = route53_client.change_resource_record_sets( 50 | HostedZoneId='Z3BEXQLL4B8OB1', 51 | ChangeBatch={ 52 | 'Changes': [ 53 | { 54 | 'Action': 'DELETE', 55 | 'ResourceRecordSet': record_sets[0] 56 | } 57 | ] 58 | } 59 | ) 60 | s3_client.delete_object(Bucket=bucket_name, Key=file_name) 61 | 62 | return { 63 | 'statusCode': 200, 64 | 'body': 'Subdomains removed successfully' 65 | } 66 | except Exception as e: 67 | return { 68 | 'statusCode': 500, 69 | 'body': str(e) 70 | } 71 | 72 | 73 | def compare_files(bucket, file1_key, file2_key, output_key): 74 | s3 = boto3.client('s3') 75 | 76 | # Download file 1 77 | file1_obj = s3.get_object(Bucket=bucket, Key=file1_key) 78 | file1_content = file1_obj['Body'].read().decode('utf-8') 79 | 80 | # Download file 2 81 | file2_obj = s3.get_object(Bucket=bucket, Key=file2_key) 82 | file2_content = file2_obj['Body'].read().decode('utf-8') 83 | 84 | # Compare the contents 85 | same_lines = [] 86 | for line in file1_content.splitlines(): 87 | if line in file2_content: 88 | same_lines.append(line) 89 | 90 | # Write same lines to the output file 91 | output_content = "\n".join(same_lines) 92 | s3.put_object(Body=output_content.encode('utf-8'), Bucket=bucket, Key=output_key) 93 | -------------------------------------------------------------------------------- /lambda_functions/enable_ssl_verify_domains.py: -------------------------------------------------------------------------------- 1 | import boto3, re, requests, json 2 | 3 | HOSTED_ZONE_ID = 'Z3BEXQLL4B8OB1' 4 | DOMAIN = 'antmedia.cloud' 5 | ec2 = boto3.resource('ec2') 6 | route53 = boto3.client('route53') 7 | URL = ":5080/WebRTCAppEE/rest/v2/version" 8 | s3_client = boto3.client('s3') 9 | BUCKET_NAME = "antmedia-subdomain-check" 10 | LAMBDA_LOCAL_TMP_FILE = '/tmp/invalid_domains-2.txt' 11 | 12 | def lambda_handler(event, context): 13 | 14 | headers = { 15 | 'Content-Type': 'application/json', 16 | } 17 | 18 | res = route53.list_resource_record_sets( 19 | HostedZoneId=HOSTED_ZONE_ID, 20 | StartRecordName='ams-*', 21 | StartRecordType='A', 22 | MaxItems='5000', 23 | ) 24 | 25 | for resource in res['ResourceRecordSets']: 26 | name = re.findall('ams-([0-9]*)', resource['Name']) 27 | if name: 28 | subdomain_list = resource['Name'][:-1] 29 | try: 30 | response = requests.get("http://" + subdomain_list + URL, headers=headers, timeout=1) 31 | response.raise_for_status() 32 | if response.status_code == 200: 33 | print("valid", subdomain_list) 34 | except requests.exceptions.RequestException as err: 35 | print("invalid", subdomain_list) 36 | with open(LAMBDA_LOCAL_TMP_FILE, 'a') as f: 37 | f.write(subdomain_list + "\n") 38 | 39 | s3_client.upload_file(LAMBDA_LOCAL_TMP_FILE, 'antmedia-subdomain-check', 'invalid_domains-2.txt') 40 | return { 41 | 'statusCode': 200, 42 | 'body': json.dumps('success') 43 | } 44 | 45 | -------------------------------------------------------------------------------- /load-testing/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /load-testing/hls_players.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | m3u8_url=$1 4 | viewers=$2 5 | 6 | for (( i=1; i <= $viewers; ++i )) 7 | do 8 | COMMAND="ffmpeg -i "$m3u8_url" -codec copy -f null /dev/null" 9 | $COMMAND &>>/dev/null & 10 | echo "running command $COMMAND" 11 | done 12 | -------------------------------------------------------------------------------- /load-testing/rtmp_publisher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file=$1 3 | server=$2 4 | noofclients=$3 5 | 6 | for (( i=1; i <= $noofclients; ++i )) 7 | do 8 | COMMAND="ffmpeg -re -stream_loop -1 -i ${file} -codec copy -f flv ${server}_${i}" 9 | $COMMAND >/dev/null 2>&1 & 10 | echo "running command $COMMAND" 11 | sleep 1 12 | done 13 | -------------------------------------------------------------------------------- /load-testing/srt_publishers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file=$1 3 | server=$2 4 | noofclients=$3 5 | 6 | for (( i=1; i <= $noofclients; ++i )) 7 | do 8 | COMMAND="ffmpeg -re -stream_loop -1 -i ${file} -codec copy -f mpegts ${server}_${i}" 9 | $COMMAND >/dev/null 2>&1 & 10 | echo "running command $COMMAND" 11 | sleep 1 12 | done 13 | -------------------------------------------------------------------------------- /monitor/datasource.json: -------------------------------------------------------------------------------- 1 | {"id":1,"orgId":1,"name":"Elasticsearch","type":"elasticsearch","typeLogoUrl":"public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg","access":"proxy","url":"http://localhost:9200","password":"","user":"","database":"logstash-*","basicAuth":false,"isDefault":true,"jsonData":{"esVersion":70,"logLevelField":"","logMessageField":"","maxConcurrentShardRequests":5,"timeField":"@timestamp"},"readOnly":false} 2 | -------------------------------------------------------------------------------- /monitor/install-graylog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | read -s -p "Enter Admin Password: " ADMIN_PASSWORD 6 | echo "" 7 | 8 | PUBLIC_IP=$(curl -s http://checkip.amazonaws.com) 9 | RED='\033[0;31m' 10 | NC='\033[0m' 11 | 12 | PASSWORD_SECRET=$(tr -dc A-Za-z0-9 /dev/null; echo "$job") | crontab - 152 | echo "Added crontab job for SSL renewal." 153 | else 154 | echo "Crontab entry for SSL renewal already exists. Skipping crontab update." 155 | fi 156 | } 157 | 158 | # Check if required options are provided 159 | if [[ $# -eq 0 ]]; then 160 | display_usage 161 | exit 1 162 | fi 163 | 164 | # Parse command-line options 165 | while getopts ":o:e:d:m:cs" opt; do 166 | case $opt in 167 | o) 168 | IFS=',' read -ra origin_server_ips <<< "$OPTARG" 169 | ;; 170 | e) 171 | IFS=',' read -ra edge_server_ips <<< "$OPTARG" 172 | ;; 173 | d) 174 | domain=$OPTARG 175 | ;; 176 | m) 177 | email=$OPTARG 178 | ;; 179 | s) 180 | ssl_enabled=true 181 | ;; 182 | c) 183 | only_nginx_configuration=true 184 | ;; 185 | \?) 186 | echo "Invalid option: -$OPTARG" >&2 187 | display_usage 188 | exit 1 189 | ;; 190 | :) 191 | echo "Option -$OPTARG requires an argument." >&2 192 | display_usage 193 | exit 1 194 | ;; 195 | esac 196 | done 197 | 198 | # Check if both origin and edge server IP arrays are provided 199 | if [[ -z "${origin_server_ips[@]}" || -z "${edge_server_ips[@]}" ]]; then 200 | echo "Missing required options: -o origin_server_ips and -e edge_server_ips." >&2 201 | display_usage 202 | exit 1 203 | fi 204 | 205 | 206 | if [[ -n "$only_nginx_configuration" ]]; then 207 | update_nginx_config 208 | echo "Nginx configuration created successfully." 209 | exit 0 210 | fi 211 | 212 | 213 | # Check if Nginx is installed 214 | if ! dpkg-query -W -f='${Status}' nginx | grep -q "installed"; then 215 | # Install Nginx 216 | install_nginx 217 | else 218 | echo "Nginx is already installed. Skipping installation." 219 | fi 220 | 221 | 222 | # Check if a domain name is provided 223 | if [[ -n "$domain" && -n "$email" ]]; then 224 | # Install Certbot and SSL certificate 225 | install_certbot 226 | install_ssl $domain $email 227 | ssl_enabled=true 228 | 229 | # Add crontab job for SSL renewal if it doesn't exist 230 | add_crontab_job "0 0 */80 * * certbot renew --nginx >/dev/null 2>&1" 231 | else 232 | echo "No domain name and email address specified. Skipping SSL certificate installation." 233 | fi 234 | 235 | # Update Nginx configuration 236 | update_nginx_config 237 | 238 | # Copy updated Nginx configuration to system's nginx.conf path 239 | sudo cp "nginx.conf" "/etc/nginx/nginx.conf" 240 | 241 | # Restart Nginx 242 | restart_nginx 243 | 244 | echo "Nginx installation and configuration complete." 245 | -------------------------------------------------------------------------------- /nginx/nginx-auto-scale.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MONGO_DB_IP="" 4 | MONGO_DB_USERNAME="" 5 | MONGO_DB_PASSWORD="" 6 | NGINX_CONF="/etc/nginx/nginx.conf" 7 | TTL="10" 8 | REGEX="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" 9 | ORIGIN_NETWORK="172.16.16.0/24" 10 | EDGE_NETWORK="172.16.17.0/24" 11 | 12 | check_packages() { 13 | if [ -z `which mongo` ]; then 14 | sudo apt-get update -qq && sudo apt-get install -y -qq mongodb-clients &> /dev/null 15 | logger "mongodb-clients package installed." 16 | fi 17 | if [ -z `which netmask` ]; then 18 | sudo apt-get update -qq && sudo apt-get install -y -qq netmask &> /dev/null 19 | logger "netmask package installed." 20 | fi 21 | 22 | } 23 | 24 | check_amscluster() { 25 | if [ -z "$MONGO_DB_USERNAME" ] && [ -z "$MONGO_DB_PASSWORD" ]; then 26 | mongo --eval 'db.clusternode.find()' clusterdb --host $MONGO_DB_IP | grep "_id" | grep -Eo "$REGEX" | sort | uniq 27 | fi 28 | 29 | if [ ! -z "$MONGO_DB_USERNAME" ] && [ ! -z "$MONGO_DB_PASSWORD" ]; then 30 | mongo --eval 'db.clusternode.find()' clusterdb --host $MONGO_DB_IP --username $MONGO_DB_USERNAME --password $MONGO_DB_PASSWORD | grep "_id" | grep -Eo "$REGEX"| sort | uniq 31 | fi 32 | } 33 | 34 | check_packages 35 | 36 | while VAR=$(check_amscluster) 37 | do 38 | for i in $VAR; do 39 | check=$(grep -o $i $NGINX_CONF|wc -l) 40 | if [[ $i =~ ^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$ ]]; then 41 | check=$(grep -o $i $NGINX_CONF|wc -l) 42 | 43 | #Scale-Out 44 | if [ "$check" == "0" ]; then 45 | if [ `netmask $i/24 -c` == "$ORIGIN_NETWORK" ]; then 46 | logger "Ant Media Cluster Origin IP Added: $i" 47 | sed -i "/upstream antmedia_origin {/a server $i:5080;" $NGINX_CONF 48 | systemctl reload nginx 49 | elif [ `netmask $i/24 -c` == "$EDGE_NETWORK" ]; then 50 | logger "Ant Media Cluster Edge IP Added: $i" 51 | sed -i "/upstream antmedia_edge {/a server $i:5080;" $NGINX_CONF 52 | systemctl reload nginx 53 | fi 54 | fi 55 | 56 | #Scale-In 57 | SCALE_OUT=$(diff <(cat $NGINX_CONF| grep -Eo "$REGEX" | sort | uniq) <(check_amscluster) --changed-group-format='%<' --unchanged-group-format='') 58 | for out in $SCALE_OUT; do 59 | if [ "$SCALE_OUT|wc -l" != "0" ]; then 60 | sed -i "/$out:5080;/d" $NGINX_CONF 61 | logger "Ant Media Cluster IP Deleted: $out" 62 | fi 63 | done 64 | fi 65 | done 66 | 67 | sleep $TTL 68 | done 69 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | # RTMP stream configuration 2 | 3 | stream { 4 | # Change {AMS_ORIGIN1_IP} and {AMS_ORIGIN2_IP} with your origin Ant Media Server instances. 5 | upstream stream_backend { 6 | {{RTMP_SERVER_BLOCKS}} 7 | #you can add more instances in the following format 8 | #server {AMS_ORIGIN1_IP}:1935; 9 | } 10 | 11 | server { 12 | listen 1935; 13 | proxy_pass stream_backend; 14 | proxy_timeout 3s; 15 | proxy_connect_timeout 1s; 16 | } 17 | 18 | # RTMPS support 19 | 20 | #ssl-disabled server { 21 | #ssl-disabled listen 1936 ssl; 22 | #ssl-disabled proxy_pass stream_backend; 23 | #ssl-disabled ssl_certificate /etc/letsencrypt/live/{{YOUR_DOMAIN}}/fullchain.pem; 24 | #ssl-disabled ssl_certificate_key /etc/letsencrypt/live/{{YOUR_DOMAIN}}/privkey.pem; 25 | #ssl-disabled } 26 | 27 | #SRT Support 28 | 29 | upstream srt_stream_backend { 30 | {{ORIGIN_SRT_SERVER_BLOCKS}} 31 | #you can add more instances in the following format 32 | #server {AMS_ORIGIN1_IP}:4200; 33 | } 34 | server { 35 | listen 4200 udp; 36 | proxy_pass srt_stream_backend; 37 | } 38 | } 39 | 40 | user nginx; 41 | worker_processes auto; 42 | pid /var/run/nginx.pid; 43 | worker_rlimit_nofile 1048576; 44 | 45 | events { 46 | worker_connections 1048576; 47 | multi_accept on; 48 | use epoll; 49 | } 50 | 51 | # Change {AMS_ORIGIN1_IP} and {AMS_ORIGIN2_IP} with your origin Ant Media Server instance addresses 52 | http { 53 | #Ant Media Origin 54 | upstream antmedia_origin { 55 | least_conn; 56 | {{ORIGIN_SERVER_BLOCKS}} 57 | {{ORIGIN_SERVER_BLOCKS_BACKUP}} 58 | #server {AMS_ORIGIN1_IP}:5080; 59 | } 60 | 61 | # Change {AMS_EDGE1_IP} and {AMS_EDGE2_IP} with your origin Ant Media Server instance addresses 62 | #Ant Media Edge 63 | upstream antmedia_edge { 64 | least_conn; 65 | {{EDGE_SERVER_BLOCKS}} 66 | {{EDGE_SERVER_BLOCKS_BACKUP}} 67 | #server {AMS_EDGE1_IP}:5080; 68 | } 69 | 70 | # Dashboard upstream setting. 71 | # Use 4444 port number to login to Dashboard. You can add Origin and Edge servers. 72 | upstream antmedia_dashboard { 73 | ip_hash; 74 | {{ORIGIN_SERVER_BLOCKS}} 75 | {{EDGE_SERVER_BLOCKS}} 76 | #server {AMS_EDGE1_IP}:5080; 77 | #server {AMS_ORIGIN1_IP}:5080; 78 | } 79 | 80 | 81 | sendfile on; 82 | client_max_body_size 250M; 83 | tcp_nopush on; 84 | tcp_nodelay on; 85 | server_tokens off; 86 | keepalive_timeout 300s; 87 | types_hash_max_size 2048; 88 | include /etc/nginx/mime.types; 89 | default_type application/octet-stream; 90 | 91 | # ssl settings 92 | ssl_protocols TLSv1.2; 93 | ssl_prefer_server_ciphers on; 94 | ssl_ciphers HIGH:!aNULL:!MD5; 95 | ssl_session_cache shared:SSL:50m; 96 | ssl_session_tickets off; 97 | 98 | # logs settings 99 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 100 | '$status $body_bytes_sent "$http_referer" ' 101 | '"$http_user_agent" "$http_x_forwarded_for"' 102 | '"$hostname" "upstream: $upstream_addr"'; 103 | access_log /var/log/nginx/access.log; 104 | error_log /var/log/nginx/error.log; 105 | 106 | # gzip 107 | gzip on; 108 | gzip_disable "msie6"; 109 | gzip_http_version 1.1; 110 | gzip_comp_level 6; 111 | gzip_types text/plain text/css application/json application/javascript text/javascript application/x-javascript text/xml application/xml application/xml+rss application/vnd.ms-fontobject application/x-font-ttf font/opentype font/x-woff image/svg+xml image/x-icon; 112 | 113 | # proxy settings 114 | proxy_redirect off; 115 | proxy_http_version 1.1; 116 | proxy_read_timeout 10s; 117 | proxy_send_timeout 10s; 118 | proxy_connect_timeout 10s; 119 | 120 | map $arg_target $origin_backend { 121 | default antmedia_origin; 122 | edge antmedia_edge; 123 | } 124 | 125 | map $arg_target $edge_backend { 126 | default antmedia_edge; 127 | origin antmedia_origin; 128 | } 129 | 130 | #80 and #443 ports go to origin group 131 | #5080 and 5443 ports go to edge group 132 | server { 133 | listen 80 default_server; 134 | server_name _; 135 | 136 | #redirect all http requests to https if ssl is enabled 137 | #ssl-disabled return 301 https://$host$request_uri; 138 | 139 | #fallback if ssl is not enabled 140 | location / { 141 | proxy_pass http://$origin_backend; 142 | proxy_http_version 1.1; 143 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 144 | proxy_set_header Host $host; 145 | proxy_set_header Upgrade $http_upgrade; 146 | proxy_set_header Connection "Upgrade"; 147 | proxy_set_header X-Forwarded-Proto https; 148 | 149 | } 150 | } 151 | 152 | # 5080 and 5443 ports go to edge group 153 | server { 154 | listen 5080; 155 | server_name _; 156 | #redirect all http requests to https if ssl is enabled 157 | #ssl-disabled return 301 https://$host:5443$request_uri; 158 | 159 | #fallback if ssl is not enabled 160 | location / { 161 | proxy_pass http://$edge_backend; 162 | proxy_http_version 1.1; 163 | proxy_connect_timeout 7d; 164 | proxy_send_timeout 7d; 165 | proxy_read_timeout 7d; 166 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 167 | proxy_set_header Host $host; 168 | proxy_set_header Upgrade $http_upgrade; 169 | proxy_set_header Connection "Upgrade"; 170 | proxy_set_header X-Forwarded-Proto https; 171 | } 172 | 173 | } 174 | 175 | #Origin Configuration 176 | #Change {{YOUR_DOMAIN}} with your fully qualified domain name. 177 | #80 and #443 ports go to origin group 178 | #ssl-disabled server { 179 | #ssl-disabled listen 443 ssl; 180 | #ssl-disabled ssl_certificate /etc/letsencrypt/live/{{YOUR_DOMAIN}}/fullchain.pem; 181 | #ssl-disabled ssl_certificate_key /etc/letsencrypt/live/{{YOUR_DOMAIN}}/privkey.pem; 182 | #ssl-disabled server_name {{YOUR_DOMAIN}}; 183 | #ssl-disabled 184 | #ssl-disabled location / { 185 | #ssl-disabled proxy_pass http://$origin_backend; 186 | #ssl-disabled proxy_http_version 1.1; 187 | #ssl-disabled proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 188 | #ssl-disabled proxy_set_header Host $host; 189 | #ssl-disabled proxy_set_header Upgrade $http_upgrade; 190 | #ssl-disabled proxy_set_header Connection "Upgrade"; 191 | #ssl-disabled } 192 | #ssl-disabled } 193 | 194 | 195 | #Edge Configuration 196 | # Change {YOUR_DOMAIN} with your fully qualified domain name. 197 | # 5080 and 5443 ports go to edge group 198 | #ssl-disabled server { 199 | #ssl-disabled listen 5443 ssl; 200 | #ssl-disabled ssl_certificate /etc/letsencrypt/live/{{YOUR_DOMAIN}}/fullchain.pem; 201 | #ssl-disabled ssl_certificate_key /etc/letsencrypt/live/{{YOUR_DOMAIN}}/privkey.pem; 202 | #ssl-disabled server_name {{YOUR_DOMAIN}}; 203 | #ssl-disabled 204 | #ssl-disabled location / { 205 | #ssl-disabled proxy_pass http://$edge_backend; 206 | #ssl-disabled proxy_http_version 1.1; 207 | #ssl-disabled proxy_connect_timeout 7d; 208 | #ssl-disabled proxy_send_timeout 7d; 209 | #ssl-disabled proxy_read_timeout 7d; 210 | #ssl-disabled proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 211 | #ssl-disabled proxy_set_header Host $host; 212 | #ssl-disabled proxy_set_header Upgrade $http_upgrade; 213 | #ssl-disabled proxy_set_header Connection "Upgrade"; 214 | #ssl-disabled } 215 | #ssl-disabled } 216 | 217 | #Dashboard Configuration 218 | #Change {YOUR_DOMAIN} with your fully qualified domain name. 219 | #ssl-disabled server { 220 | #ssl-disabled listen 4444 ssl; 221 | #ssl-disabled ssl_certificate /etc/letsencrypt/live/{{YOUR_DOMAIN}}/fullchain.pem; 222 | #ssl-disabled ssl_certificate_key /etc/letsencrypt/live/{{YOUR_DOMAIN}}/privkey.pem; 223 | #ssl-disabled server_name {{YOUR_DOMAIN}}; 224 | #ssl-disabled 225 | #ssl-disabled location / { 226 | #ssl-disabled proxy_pass http://antmedia_dashboard; 227 | #ssl-disabled proxy_http_version 1.1; 228 | #ssl-disabled proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 229 | #ssl-disabled proxy_set_header Host $host; 230 | #ssl-disabled proxy_set_header Upgrade $http_upgrade; 231 | #ssl-disabled proxy_set_header Connection "Upgrade"; 232 | #ssl-disabled } 233 | #ssl-disabled } 234 | 235 | server { 236 | listen 4445; 237 | server_name {{YOUR_DOMAIN}}; 238 | 239 | location / { 240 | proxy_pass http://antmedia_dashboard; 241 | proxy_http_version 1.1; 242 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 243 | proxy_set_header Host $host; 244 | proxy_set_header Upgrade $http_upgrade; 245 | proxy_set_header Connection "Upgrade"; 246 | } 247 | 248 | } 249 | 250 | 251 | } 252 | -------------------------------------------------------------------------------- /pre_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script creates user for standalone aws server and cloudformation template. 4 | # 5 | 6 | INITIALIZED=/usr/local/antmedia/conf/initialized 7 | if [ ! -f "$INITIALIZED" ] 8 | then 9 | TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 10 | 11 | 12 | 13 | export INSTANCE_ID=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id` 14 | 15 | 16 | SECRET_KEY=$(echo -n $INSTANCE_ID | md5sum | awk '{print $1}' ) 17 | echo $SECRET_KEY > /usr/local/antmedia/SECRET_KEY 18 | sudo sed -i "/^server.jwtServerControlEnabled=/s|.*|server.jwtServerControlEnabled=true|" /usr/local/antmedia/conf/red5.properties 19 | sudo sed -i "/^server.jwtServerSecretKey=/s|.*|server.jwtServerSecretKey=$SECRET_KEY|" /usr/local/antmedia/conf/red5.properties 20 | 21 | TAG_VALUE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/tags/instance/auto-managed-ams) 22 | # Get the value of the "auto-managed-ams" tag 23 | 24 | if [ "$TAG_VALUE" = "true" ]; then 25 | echo "This instance is auto-managed by Ant Media CloudFormation template" 26 | 27 | export PUBLIC_IPv4=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4` 28 | 29 | export FQDN="ams-${PUBLIC_IPv4//./-}.antmedia.cloud" 30 | sudo echo $FQDN > /usr/local/antmedia/fqdn 31 | cd /usr/local/antmedia 32 | sudo ./enable_ssl.sh -d $FQDN > /usr/local/antmedia/enable_ssl.log 33 | else 34 | echo "This instance is not auto-managed" 35 | 36 | fi 37 | 38 | fi -------------------------------------------------------------------------------- /prepare_changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Prepare change log clones the following repositories and creates change log since latest tag 5 | # "Ant-Media-Server" 6 | # "Ant-Media-Enterprise" 7 | # "Ant-Media-Management-Console" 8 | # "StreamApp" 9 | # "Ant-Media-Server-Parent" 10 | 11 | # Usage 12 | # ./prepare_change_log [BRANCH_NAME] [TAG] 13 | # 14 | # BRANCH_NAME is the branch where change log will be created. It's optional. 15 | # TAG is the tag where change log will be created since then. It's optional. If not specified, it will create the changelog 16 | # since the last tag 17 | # 18 | # Important: To get MR from gitlab, there should be environment variable(GITLAB_TOKEN) exported with valid token 19 | # To get PR from github, there should be environment variable(GITHUB_TOKEN) exported with valid token 20 | # 21 | 22 | 23 | 24 | BRANCH_NAME=$1 25 | TAG=$2 26 | CHANGE_LOG=`pwd`/changelog.html 27 | 28 | get_change_log() 29 | { 30 | GIT_URL=$1 31 | FOLDER=$2 32 | PULL_REQUEST_BASE_URL=$3 33 | 34 | if [ $(git ls-remote $GIT_URL $BRANCH_NAME | wc -l) == "1" ]; 35 | then 36 | echo " $BRANCH_NAME branch found"; 37 | git clone --depth=200 -b $BRANCH_NAME $GIT_URL $FOLDER; 38 | 39 | else 40 | echo "branch not found. Checking out master"; 41 | git clone --depth=200 $GIT_URL $FOLDER; 42 | fi 43 | 44 | cd $FOLDER 45 | if [ ! -n "$TAG" ]; then 46 | echo "TAG parameter not supplied."; 47 | TAG=`git tag --sort=-creatordate | head -n 1`; 48 | fi 49 | 50 | DATE_OF_THE_TAG=`git log -1 --date=iso-strict --pretty=format:%ad $TAG` 51 | 52 | echo "

$FOLDER

" >> $CHANGE_LOG 53 | gh pr list --search "merged:>$DATE_OF_THE_TAG" -L 1000 --json title,body,number --template "{{range .}}
  • {{.number}} {{.title}} - {{.body}}
  • {{end}}" >> $CHANGE_LOG 54 | 55 | cd .. 56 | 57 | } 58 | 59 | rm -f $CHANGE_LOG 60 | touch $CHANGE_LOG 61 | 62 | #get Ant Media Server 63 | export GH_REPO=ant-media/Ant-Media-Server 64 | export GH_HOST=github.com 65 | get_change_log https://github.com/ant-media/Ant-Media-Server.git Ant-Media-Server https://github.com/ant-media/Ant-Media-Server 66 | 67 | #get Ant Media Server Enterprise log 68 | if [ ! -n "$TAG" ]; then 69 | echo "TAG parameter not supplied."; 70 | TAG=`git tag --sort=-creatordate | head -n 1`; 71 | fi 72 | echo "

    Ant-Media-Enterprise

    " >> $CHANGE_LOG 73 | 74 | DATE_OF_THE_TAG=`git log -1 --date=iso-strict --pretty=format:%ad $TAG` 75 | curl --location --request GET "https://gitlab.com/api/v4/projects/5032874/merge_requests?state=merged&view=simple&per_page=100&updated_after=$DATE_OF_THE_TAG" --header "Authorization: Bearer $GITLAB_TOKEN" 2>/dev/null | jq -r ' .[] | "
  • \(.title)- \(.description)
  • "' >> $CHANGE_LOG 76 | 77 | # "StreamApp" 78 | export GH_REPO=ant-media/StreamApp 79 | get_change_log https://github.com/ant-media/StreamApp.git StreamApp https://github.com/ant-media/StreamApp 80 | 81 | # "Ant-Media-Server-Parent" 82 | export GH_REPO=ant-media/ant-media-server-parent 83 | get_change_log https://github.com/ant-media/ant-media-server-parent.git Ant-Media-Server-Parent https://github.com/ant-media/ant-media-server-parent 84 | 85 | # "Ant-Media-Management-Console" 86 | export GH_REPO=ant-media/Ant-Media-Management-Console 87 | get_change_log https://github.com/ant-media/Ant-Media-Management-Console.git Ant-Media-Management-Console https://github.com/ant-media/Ant-Media-Management-Console 88 | -------------------------------------------------------------------------------- /vod_transcode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This bash script converts your VoD files to HLS format. (720p, 480p, 240p) 4 | # 5 | # Installation Instructions 6 | # sudo apt-get update && sudo apt-get install ffmpeg -y 7 | # switch to application advance properties and set the property, 8 | # "vodUploadFinishScript": "/path/to/vod_transcode.sh ", 9 | # sudo service antmedia restart 10 | 11 | # Don't forget to change the Ant Media Server App Name in which you want to save the files 12 | AMS_APP_NAME="WebRTCAppEE" 13 | 14 | file=$1 15 | file_name=$(basename $file .mp4) 16 | 17 | # Bitrates and resolutions 18 | resolutions=("1280x720" "640x480" "320x240") 19 | bitrates=("2500k" "1500k" "800k") 20 | names=("720p" "480p" "240p") 21 | 22 | cd /usr/local/antmedia/webapps/$AMS_APP_NAME/streams/ 23 | 24 | # Create directories for each resolution 25 | for name in "${names[@]}"; do 26 | mkdir -p ${file_name}_${name} 27 | done 28 | 29 | $(command -v ffmpeg) -i $file \ 30 | -map 0:v -map 0:a -s:v:0 ${resolutions[0]} -c:v:0 libx264 -b:v:0 ${bitrates[0]} \ 31 | -map 0:v -map 0:a -s:v:1 ${resolutions[1]} -c:v:1 libx264 -b:v:1 ${bitrates[1]} \ 32 | -map 0:v -map 0:a -s:v:2 ${resolutions[2]} -c:v:2 libx264 -b:v:2 ${bitrates[2]} \ 33 | -c:a aac -f hls -hls_playlist_type vod \ 34 | -master_pl_name ${file_name}.m3u8 \ 35 | -hls_segment_filename ${file_name}_%v/${file_name}%04d.ts \ 36 | -var_stream_map "v:0,a:0,name:720p v:1,a:1,name:480p v:2,a:2,name:240p" \ 37 | ${file_name}_%v/${file_name}.m3u8 38 | --------------------------------------------------------------------------------