I have deployed my django backend api on Amazon Ec2 using docker successfully.
My first step is when I attempted to put in a dockerized Nginx to act as a reverse proxy. I then eventually intend to use for Static media files caching and a dedicated live media streaming server. I'm using the following repo https://github.com/tiangolo/nginx-rtmp-docker/tree/master which installs the necessary nginx modules including the rtmp module which i need later.
However , There is no response from the nginx side when it comes to Reverse proxy which is the 1st configuration I'm testing.
The following is what I have checked.
- Added port 70 as listen port for EC2 in Security groups - custom tcp.
- Both the containers are running by checking docker stats
- The ports are mapped correctly by checking the port mappings using docker ps.
- Used netstat to check if the the port is listed after I spun up the 2 containers and both 70 (nginx listen port) and 80 (api listen port) are listed.
- The api server still works when I hit the public static IP of my EC2 server 34.XX.XX.XX:80/ but not when I hit 34.XX.XX.XX:70/ which should proxy requests to the port 80.
Here is my configuration. Kindly note I'm not attaching the configuration for postgresql-db and redis-db in the docker-compose.yml since I believe they are not relevant to the question but they are the other 2 containers listening on other ports.
docker-compose.yml
services:
webserver:
container_name: myapp-api
build:
dockerfile: Dockerfile
context: ./.docker/api
privileged: True
extra_hosts:
- db.myapp:172.16.16.4
- redis.myapp:172.16.16.5
volumes:
- ./:/opt/myapp-api-core
ports:
- '80:8080' # External listen port 80 mapped to interal docker port 8080
working_dir: /opt/myapp-api-core
networks:
myapp:
ipv4_address: 172.16.16.1
depends_on:
- db
- redis
env_file:
- .docker-compose.env
nginx-media_server:
container_name: myapp-nginx-media-server
build:
dockerfile: Dockerfile
context: ./.docker/nginx-media-server
ports:
- 70:1652 # External Caching server listen port mapped to internal docker container port 1652.
volumes:
- ./.docker-cache/static:/tmp/nginx
- ./.docker/nginx-media-server/nginx.conf:/etc/nginx/nginx.conf
- ./.docker/nginx-media-server/log:/var/log/nginx # Logs
networks:
myapp:
ipv4_address: 172.16.16.6
env_file:
- .docker-compose.env
nginx.conf
worker_processes auto;
events {
use epoll;
}
# HTTP block
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $request_time';
# Access & Error Logs
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
default_type application/octet-stream;
include /etc/nginx/mime.types;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Increase the maximum size of the hash table
proxy_headers_hash_max_size 1024;
# Increase the bucket size of the hash table
proxy_headers_hash_bucket_size 128;
#Note that these are defined outside of the server block altho they don't necessarily need to be
proxy_cache_path /tmp/nginx levels=1:2 keys_zone=my_zone:10m inactive=60m max_size=20g;
proxy_cache_key "$scheme$request_method$host$request_uri";
server {
listen 70 default_server;
server_name _;
access_log /var/log/nginx/access.log ;
error_log /var/log/nginx/error.log;
location / {
proxy_cache my_zone;
proxy_cache_bypass $http_cache_control;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
include proxy_params;
proxy_pass http://172.16.16.1:8080;
# WebSocket support (nginx 1.4)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
Dockerfile (Nginx media server)
FROM buildpack-deps:bullseye
LABEL maintainer="Sebastian Ramirez <tiangolo@gmail.com>"
# Versions of Nginx and nginx-rtmp-module to use
ENV NGINX_VERSION nginx-1.23.2
ENV NGINX_RTMP_MODULE_VERSION 1.2.2
# Install dependencies
RUN apt-get update && \
apt-get install -y ca-certificates openssl libssl-dev && \
rm -rf /var/lib/apt/lists/*
# Download and decompress Nginx
RUN mkdir -p /tmp/build/nginx && \
cd /tmp/build/nginx && \
wget -O ${NGINX_VERSION}.tar.gz https://nginx.org/download/${NGINX_VERSION}.tar.gz && \
tar -zxf ${NGINX_VERSION}.tar.gz
# Download and decompress RTMP module
RUN mkdir -p /tmp/build/nginx-rtmp-module && \
cd /tmp/build/nginx-rtmp-module && \
wget -O nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
tar -zxf nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
cd nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}
# Build and install Nginx
# The default puts everything under /usr/local/nginx, so it's needed to change
# it explicitly. Not just for order but to have it in the PATH
RUN cd /tmp/build/nginx/${NGINX_VERSION} && \
./configure \
--sbin-path=/usr/local/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/tmp/nginx-client-body \
--with-http_ssl_module \
--with-threads \
--with-ipv6 \
--add-module=/tmp/build/nginx-rtmp-module/nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION} --with-debug && \
make -j $(getconf _NPROCESSORS_ONLN) && \
make install && \
mkdir /var/lock/nginx && \
rm -rf /tmp/build
# Forward logs to Docker
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
# Set up config file
COPY nginx.conf /etc/nginx/nginx.conf
# Install ffmpeg
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get install -y ffmpeg
VOLUME ["/tmp/nginx","/etc/nginx/nginx.conf","/var/log/nginx"]
# Expose internal docker ports attached to external receiver ports.
EXPOSE 1652
CMD ["nginx", "-g", "daemon off;"]
EDIT :
Based on the questions posted by @0xn0b174 -->
can you check the inbound rule for port 70 in you ec2 Security group what have you addded ??
Port Source Protocol Description
70 0.0.0.0/0 TCP NGINX Caching server
you have mapped 1652 docker port to port 70 can you confrim your service is running in 1652 inside docker container.
can you share the ouput of docker exec -it myapp-nginx-media-server ping 172.16.16.1
OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown
lastly can you tail and share /var/log/nginx/error.log and docker logs docker logs myapp-nginx-media-server
Shows logs from a few hourse before, the errors of which have been already corrected. Used the docker copy command
2024/09/07 04:16:46 [emerg] 1#1: invalid log level "main" in /etc/nginx/nginx.conf:16
2024/09/07 04:18:21 [emerg] 1#1: invalid log level "main" in /etc/nginx/nginx.conf:16
2024/09/07 06:22:32 [emerg] 1#1: host not found in upstream "api:8080" in /etc/nginx/nginx.conf:187
2024/09/07 06:24:37 [emerg] 1#1: invalid host in upstream "http://172.16.16.1:8080/" in /etc/nginx/nginx.conf:187
2024/09/07 06:27:15 [emerg] 1#1: invalid host in upstream "http://172.16.16.1:8080/" in /etc/nginx/nginx.conf:187
2024/09/07 07:27:28 [notice] 11#11: signal process started
2024/09/07 07:27:31 [notice] 20#20: signal process started
2024/09/07 07:29:01 [emerg] 1#1: unexpected end of file, expecting "}" in /etc/nginx/nginx.conf:444
docker.logs
docker logs --since=1h cc1274f259d4 > /home/ubuntu/docker_logs.txt
Above log is empty
EDIT 2:
I did a clean install. The nginx error.log and access.log is empty. The ports are correctly mapped after check docker ps.
I entered the nginx container and did a nginx -t
I got this:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
your setup should be pretty easy, not sure why are you complicating binding diffrent ports but here is nginx and docker conatiner simple setup to run in ec2:
docker-compose.yml
services:
web:
container_name: django-api
build:
context: ./django
dockerfile: Dockerfile
volumes:
- ./django/app:/app
expose:
- "8000" # Expose internal Django port
networks:
- myapp-network
nginx:
container_name: nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- "80:80" # Expose port 80 for the public to access
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
networks:
- myapp-network
networks:
myapp-network:
driver: bridge
./django/Dockerfile
# Use official Python image from the dockerhub
FROM python:3.9-slim
# Set work directory
WORKDIR /app
# Install dependencies
COPY ./app /app
RUN pip install --upgrade pip && \
pip install -r /app/requirements.txt
# Expose port
EXPOSE 8000
# Command to run the app
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
./nginx/Dockerfile
FROM nginx:alpine
# Copy the custom nginx.conf to the container
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
./nginx/nginx.conf
worker_processes auto;
events { worker_connections 1024; }
http {
upstream django {
server web:8000; # The internal Django API service
}
server {
listen 80;
location / {
proxy_pass http://django;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
If you can imitate this setup you should be good to go.