Skip to content

Instantly share code, notes, and snippets.

@vicradon
Last active June 6, 2024 09:03
Show Gist options
  • Save vicradon/190247cdf3b5a40c35f2d6bc0597c227 to your computer and use it in GitHub Desktop.
Save vicradon/190247cdf3b5a40c35f2d6bc0597c227 to your computer and use it in GitHub Desktop.
How does Nginx Work?

How Nginx Works

Nginx works using configuration files. You define a configuration for a single site or all the sites in a machine and Nginx serves the content of that defined site. In the past, folks defined new sites in the /etc/nginx/sites-available and /etc/nginx/sites-enabled directories. These days, Nginx suggests that you use the conf.d directory. The default Nginx config serves the default Nginx page, i.e. welcome to Nginx. But you can easily replace it with something simple that reverse proxies your requests. Something like this:

http {
    server {
        listen 80;

        location / {
            proxy_pass http://127.0.0.1:5000;
            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;
        }
    }
}

The config above serves the machine assigned interfaces on port 80 but proxies the services running on port 5000 to it. This is by far the cleanest way to serve your custom apps on port 80, rather than using sudo to force them to bind to port 80.

If you say, have a subdomain that you want to proxy requests through, you can define this config in the conf.d directory. You simply have to define the server_name which will be a subdomain that points to the IP address assigned to your machine via an A record. You should configure this subdomain both for the standard subdomain and www. This way, you handle all cases of people trying to reach your website. The proxy_pass in the location block is the same as you saw earlier. It proxies requests sent to these subdomains to the service running on port 8089.

server {
    listen 80;
    server_name ubuntuserver.osinachi.me www.ubuntuserver.osinachi.me;

    location / {
        proxy_pass http://localhost:8089;
    }
}

After saving your file, say ubuntuserver.conf in the conf.d directory, you simply need to reload Nginx. This can be achieved using the command sudo nginx -s reload. Nginx can now handle serving your app content.

Serving Python via Nginx

You can and should serve a Python service via Nginx to port 80 on the Docker container. Why tho? Because it makes deployment to a cloud service a breeze. The cloud provider won't have to provision port mapping. Your app just works!

So you have your Dockerfile defined as:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . /app/

EXPOSE 5000

CMD python app.py

This Dockerfile runs a Flask application on port 5000. Simple enough. But that's what we don't want. We want port 80. Well... just install Nginx then:

...
RUN apt-get update && apt-get install -y nginx

COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD service nginx start && python app.py

Notice anything missing in what was added above? Yes, there's a COPY command copying nginx.conf into the container. So define this config to be something like:

http {
    server {
        listen 80;

        location / {
            proxy_pass http://127.0.0.1:5000;
            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;
        }
    }
}

This is the default Nginx configuration and it serves as a one-off use Nginx, existing simply to serve this Flask service on port 80. It is copied to the Docker image's /etc/nginx/nginx.conf file.

With all that done, your app should serve it's content on port 80. Here's the complete Dockerfile:

FROM python:3.9-slim AS flask-build

WORKDIR /app

COPY requirements.txt .

RUN python -m venv .venv
RUN . .venv/bin/activate
RUN pip install -r requirements.txt

COPY . /app/

RUN apt-get update && apt-get install -y nginx

COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

STOPSIGNAL SIGINT

CMD service nginx start && python app.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment