Serving django static files in nginx docker

Hey all, I am at a loss – I’ve gone through all the posts related to my problem, but I still cannot get my static css and js files to format my content in my Django site when running via docker and nginx.

Here are some relevant configurations from my settings.py file:

DEBUG = True
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'web.apps.WebConfig',
    'django_recaptcha'
]
WSGI_APPLICATION = 'portfolio.wsgi.application'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

Here is my Dockerfile:

FROM python:3.11-slim

WORKDIR opt/django/
COPY pyproject.toml .
RUN python -m pip install . -I --no-cache-dir

COPY ./portfolio/ ./portfolio/

WORKDIR portfolio/

RUN python manage.py collectstatic --noinput
RUN python manage.py makemigrations
RUN python manage.py migrate

EXPOSE 8000

CMD ["gunicorn", "portfolio.wsgi:application", "--bind", "0.0.0.0:8000"]

Here is my docker-compose.yml:

#version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: ./docker/Dockerfile_django
    container_name: webserver
    volumes:
      - static_data:/opt/django/portfolio/static
    expose:
      - "8000"
    ports:
      - "8000:8000"
    depends_on:
      - db

  db:
    image: postgres:15
    container_name: db_postgres
    expose:
      - "5432"
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres

  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - static_data:/opt/django/portfolio/static
    depends_on:
      - web

volumes:
  postgres_data:
  static_data:

And finally, here is my nginx.conf:


http {
    server {
        listen 80;
        server_name localhost;

        location /static {
            alias /opt/django/portfolio/static;
            autoindex on;
            access_log /var/log/nginx/static_access.log;
            error_log /var/log/nginx/static_error.log debug;
        }

        # skip favicon.ico
        location /favicon.ico {
            access_log off;
            return 204;
        }

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

        error_log /var/log/nginx/error.log debug;

    }
}

I see no errors in my logs, and nginx is reporting 200’s when I make a GET to a url in the project. When I visit http://127.0.0.1/static/website/style.css I can see the css. I’ve cleared my cache. When I go to /opt/django/portfolio/collectstatic in my web and nginx containers, I can see the static files. I have also tried updating permissions on the static files by running: chmod -R 755 /opt/django/portfolio/static/website/style.css in both the nginx and web containers.

My project is structured like this:

 - portfolio/
   - nginx/
     - nginx.conf
   - portfolio/
     - portfolio/
       - settings.py
       - ...
     - web/
       - js/
         - somejs.js
         - someotherjs.js
       - website/
         - style.css
       - admin.py
       - apps.py
       - forms.py
       - models.py
       - tests.py
       - ...

What am I missing? Below is a snippet of the logs from my nginx container. Is the timeout indicative of anything?

nginx        | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:51:06 +0000] "GET / HTTP/1.1" 200 2458 "http://0.0.0.0/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:51:08 +0000] "GET /about HTTP/1.1" 200 2304 "http://0.0.0.0/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:51:39 +0000] "GET /about HTTP/1.1" 200 2304 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:52:04 +0000] "GET /tictactoe/ HTTP/1.1" 200 5181 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:52:05 +0000] "GET /tictactoe/?difficulty=All HTTP/1.1" 200 155 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 2024/08/18 16:52:06 [info] 29#29: *1 client timed out (110: Connection timed out) while waiting for request, client: 192.xxx.xx.x, server: 0.0.0.0:80
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:52:39 +0000] "GET /about HTTP/1.1" 200 2304 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:52:55 +0000] "GET /about HTTP/1.1" 200 2304 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.xxx.xx.x - - [18/Aug/2024:16:53:05 +0000] "GET / HTTP/1.1" 200 2458 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"

Welcome @fredonia88 !

This:

Should be run before you ever get to this point. You don’t want to be creating migrations arbitrarily when the container is being built. This is something that should be done in development and checked in to your repository.

These commands:

need to run at run time, not docker build time. These commands should be in the script that runs when the container is executed.

One way of doing this is to replace this:

With a CMD directive to run a script containing all three commands. (The collectstatic, migrate and gunicorn commands.)

Thanks for the speedy reply @KenWhitesell !

I made the suggested changes, but am still not seeing any formatting.

Here is my new Dockerfile:

FROM python:3.11-slim

WORKDIR opt/django/
COPY pyproject.toml .
RUN python -m pip install . -I --no-cache-dir

COPY ./portfolio/ ./portfolio/

WORKDIR portfolio/

COPY start.sh /start.sh

RUN chmod +x /start.sh

EXPOSE 8000

CMD ["/start.sh"]

Here’s the new script to run the commands:

#!/bin/bash

# collect static files and migrate
python manage.py collectstatic --noinput
python manage.py migrate

# start gunicorn server
gunicorn portfolio.wsgi:application --bind 0.0.0.0:8000

No changes made to nginx.conf or docker-compose.yml. Any other ideas? I don’t see anything in the logs:

nginx        | 192.xxx.xx.x - - [18/Aug/2024:18:24:51 +0000] "GET /about HTTP/1.1" 200 2304 "http://127.0.0.1/contact" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
nginx        | 192.1xxx.xx.x - - [18/Aug/2024:18:24:52 +0000] "GET / HTTP/1.1" 200 2458 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36

What I’m not seeing are any requests for those css files.

Please show the view for any one view that is supposed to be referencing a css file, along with the template being rendered.

Also look at the error log, along with checking the docker logs for those containers.

Here is the home view:

class HomeView(View):
    template_name = 'home.html'

    def get(self, request):

        return render(request, self.template_name)

Here is the url pattern:

urlpatterns = [
    path('', HomeView.as_view(), name="home")
    ...

Finally, here is home.html:

{% extends 'base.html' %}

{% load static %}
<head>
  <link rel="stylesheet", type="text/css", href="{% static 'website/style.css' %}">
</head>

{% block content %}

<p style="margin-left: 40px; text-align: left;">
<br>
Here is some content!
</p>

{% endblock %}

In the nginx docker logs, I do see these:

2024-08-18 13:21:50 2024/08/18 18:21:50 [info] 29#29: *1 client 192.xxx.xx.x closed keepalive connection
2024-08-18 13:22:07 2024/08/18 18:22:07 [info] 29#29: *4 client timed out (110: Connection timed out) while waiting for request, client: 192.xxx.xx.x, server: 0.0.0.0:80

My static_error.log in /var/log/nginx/ is empty, but the static_access.log shows entries. Here are two:

192.xxx.xx.x - - [18/Aug/2024:18:27:59 +0000] "GET /static/website/style.css HTTP/1.1" 304 0 "http://127.0.0.1/contact" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:18:27:59 +0000] "GET /static/js/contact.js HTTP/1.1" 304 0 "http://127.0.0.1/contact" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"

A 304 is a file not-modified condition, which means it’s already cached in your browser and the browser isn’t retrieving it.

Try accessing your page using your browser in “incognito” or “private” mode. You can also try doing a force reload (shift-f5). You can also try clearing your browser cache for your site.

Side note: Please confirm that you are stopping and rebuilding your containers after every change.

Sadly, I still don’t see any formatting. I’ve opened a new incognito tab and have been forcing the browser to retrieve the html with command + shift + R (mac). Still no luck. I’ve also tried this in Safari (I’ve been using chrome).

I can confirm I am stopping and rebuilding all containers. In fact, this last go, I deleted everything – dangling images, volumes and builds and rebuilt the image using no cached files.

Here’re more nginx logs:

2024-08-18 16:15:33 192.xxx.xx.x - - [18/Aug/2024:21:15:33 +0000] "GET /about HTTP/1.1" 200 2304 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:15:54 192.xxx.xx.x - - [18/Aug/2024:21:15:54 +0000] "GET /tictactoe/ HTTP/1.1" 200 5181 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:15:54 192.xxx.xx.x - - [18/Aug/2024:21:15:54 +0000] "GET /tictactoe/?difficulty=All HTTP/1.1" 200 155 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:17:10 192.xxx.xx.x - - [18/Aug/2024:21:17:10 +0000] "GET /tictactoe/ HTTP/1.1" 200 5181 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:17:10 192.xxx.xx.x - - [18/Aug/2024:21:17:10 +0000] "GET /tictactoe/?difficulty=All HTTP/1.1" 200 155 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:17:11 192.xxx.xx.x - - [18/Aug/2024:21:17:11 +0000] "GET / HTTP/1.1" 200 2458 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:17:34 192.xxx.xx.x - - [18/Aug/2024:21:17:34 +0000] "GET / HTTP/1.1" 200 2458 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
2024-08-18 16:17:15 2024/08/18 21:17:15 [info] 29#29: *13 client 192.xxx.xx.x closed keepalive connection
2024-08-18 16:17:15 2024/08/18 21:17:15 [info] 29#29: *15 client 192.xxx.xx.x closed keepalive connection

Screenshot of the unformatted site:

FWIW: I am using python 3.11 and below are the python package versions I’m using:

    "asgiref==3.8.1",
    "certifi==2024.7.4",
    "Django==5.0.7",
    "django-recaptcha==4.0.0",
    "gunicorn==22.0.0",
    "packaging==24.1",
    "sqlparse==0.5.1"

It’s the static logs that we need to see. We need to verify that nginx is getting requests for those css files and serving them.

In addition to checking the logs, you’ll want to check the data volume to verify that the current css files are in it.

I checked the volume and all the static files are there:

The static_error.log in nginx container is empty, but the static_access.log has entries. Looks to be retrieving the static files ok (mix of 200 and 304):

# cat static_access.log
192.xxx.xx.x - - [18/Aug/2024:21:15:27 +0000] "GET /static/js/tictactoe.js HTTP/1.1" 200 7267 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:21:15:30 +0000] "GET /static/js/contact.js HTTP/1.1" 200 471 "http://127.0.0.1/contact" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:21:17:10 +0000] "GET /static/website/style.css HTTP/1.1" 200 2511 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:21:17:10 +0000] "GET /static/js/tictactoe.js HTTP/1.1" 200 7267 "http://127.0.0.1/tictactoe/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:21:17:34 +0000] "GET /static/website/style.css HTTP/1.1" 200 2511 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [18/Aug/2024:21:26:39 +0000] "GET /static/website/style.css HTTP/1.1" 304 0 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [19/Aug/2024:00:10:10 +0000] "GET /static/website/style.css HTTP/1.1" 304 0 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [19/Aug/2024:00:11:56 +0000] "GET /static/website/style.css HTTP/1.1" 200 2511 "http://127.0.0.1/about" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
192.xxx.xx.x - - [19/Aug/2024:00:12:44 +0000] "GET /static/website/style.css HTTP/1.1" 200 2511 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"

Are the contents correct in those static files?

Also, I’m not familiar with the tool you’re using.

Your docker compose file shows that the volume name is static_data, but that tool is showing a volume named portfolio_static_data?

If you look at the css file in the browser, are you seeing the current contents?

Yes, the content in the volume files matches what I have in the repo. The tool I am using is Docker Desktop, running locally on my mac.

I believe it is normal for Docker to prefix volume names with the project name to avoid collisions. To be sure, I added portfolio_ to the volume names in docker-compose, rebuilt the image and redeployed, but now portfolio_portfolio_ is appended to the volume name in Docker Desktop.

When I look at the css in the browser, (i.e. I ping http://127.0.0.1/static/website/style.css or http://127.0.0.1/static/js/contact.js) I can see the plain css or javascript in the browser. It matches what is in my repo.

Ok, I’m talking about the css that was loaded by the page when you examine the page using the browser’s developer tools.

If you examine the page, there’s a tab “sources”. If you look at your style.css file in the sources, what do you see?

If you click on an element in the “Elements” tab that should be styled by your “style.css” file, does it show up as being styled by that element?

Also, I just noticed that your link to the stylesheet is not in a block - is it even being rendered in the page? You’ve also got it in a <head> element. Is it functional if you have two separate <head> elements in the page?
What does your base.html look like?

Ok, I’m talking about the css that was loaded by the page when you examine the page using the browser’s developer tools.

If you examine the page, there’s a tab “sources”. If you look at your style.css file in the sources, what do you see?

If you click on an element that should be styled in the “Elements” tab, do you see it being styled by your css file?

Also, I just noticed that your link to the stylesheet is not in a block - is it even being rendered in the page? You’ve also got it in a <head> element. Is it functional if you have two separate <head> elements in the page? What does your base.html` look like?

OK, your last comment is heading in the right direction.

When I click on sources, I can see the static files:

If I click on an element, all of the generated html looks correct to me despite no css being rendered. For example, my css style sheet contains:

.bg {
    background-color: black;
}

And I can see that element in the html, but it is not being styled (i.e. the background is not black):

However, if I make an entry in the body element with --bs-body-color: black the background successfully changes to black!

In terms of being functional, all of this works locally when I’m running with DEBUG=True via runserver. Here is the base.html file:

And here is the home.html page (this is the html being loaded in the first two screenshots):

Note that you have two commas in this <link>` tag, but they shouldn’t be there. HTML tags don’t have commas in them (unless they’re in quoted attribute values). That might be causing the problem:

Thank you for catching that. I made the update to all html files, but still do not have any formatting (rebuilt image and containers from scratch, and visited site in incognito window).

An HTML page should only have one <head> element. Your base.html has two and then you’re trying to add another in your home.html.

You should only have one in your base.html and then use a block within that which child templates can use to insert extra <link> tags etc. Here’s a very basic example:

base.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  {% load static %}
  <link rel="stylesheet" type="text/css" href="{% static 'bootstrap.css' %}">
  {% block extra_css }
  {% endblock %}
</head>
<body>
  
</body>
</html>

home.html:

{% extends "base.html" %}
{% load static %}

{% block extra_css %}
  <link rel="stylesheet" type="text/css" href="{% static 'website/style.css' %}">
{% endblock %}

NOTE: This isn’t exactly what yours should look like but because you posted images instead of actual code, I can’t copy and paste from your HTML.

I made those updates. Still no formatting running through nginx!

Here is base.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}Portfolio{% endblock %}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="some-sha-key" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css?family=Fira Code" rel="stylesheet">
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'website/style.css' %}">
  </head>
  <body class="bg">
    {% include 'navbar.html' %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="some-sha-key="anonymous"></script>
  </body>
  </br>
  <div class="container-fluid">
    {% block content %}

    {% endblock %}
  </div>
</html>

And here is home.html:

{% extends 'base.html' %}
{% load static %}

{% block content %}
<p style="margin-left: 40px; text-align: left;">
<br>
Hey, I'm so-and-so, Senior Data Engineer based out of some place. Check out my portfolio, and feel free to get in touch.
</p>

{% endblock %}

And here is navbar.html if it helps:

<nav class="navbar navbar-expand-lg">
  <div class="container-fluid">
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
              <li class="nav-item">
                <a class="nav-link nav-custom" aria-current="page" href="{% url 'home' %}">Home</a>
              </li>
          </ul>
          <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <a class="nav-link nav-custom" aria-current="page" href="{% url 'about' %}">About</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                    Projects
                </a>
                <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown" style="padding: 0;">
                    <li><a class="dropdown-item" href="{% url 'tictactoe' %}">Tic Tac Toe</a></li>
                    <li><a class="dropdown-item" href="{% url 'ercot' %}">Ercot Renewable Energy Demand</a></li>
                    <li><a class="dropdown-item" href="{% url 'bls' %}">Bureau of Labor Statistics</a></li>
                </ul>
            </li>
            <li class="nav-item">
              <a class="nav-link nav-custom" aria-current="page" href="{% url 'contact' %}">Contact</a>
            </li>
          </ul>
      </div>
  </div>
</nav>

I’m happy to report I solved the issue by adding include mime.types; under location /static { in my nginx.conf file.

Thank you both @KenWhitesell and @philgyford ! I’m not sure I’ll use nginx after this.