gpodder / mygpo

The gpodder.net webservice
http://gpodder.net/
GNU Affero General Public License v3.0
273 stars 85 forks source link

Sample Nginx configuration #531

Open maxolasersquad opened 3 years ago

maxolasersquad commented 3 years ago

I am attempting to install my own mygpo backend on my home server. It is ~95% working. I think some of the issues I'm continuing to bump in to may be related to my Nginx configuration. Here is what I have so far.

server {
    listen 80;
    server_name podcast.myservice.com;

    location / {
        proxy_pass http://192.168.1.23:8080/;
    }

    location /static {
        alias /home/gpodder/mygpo/staticfiles/;
    }

    location /favicon.png {
        alias /home/gpodder/mygpo/static/favicon.png;
    }
}

The service is started with systemd using the following ExecStart command.

/home/gpodder/mygpo/venv/bin/envdir /home/gpodder/mygpo/envs/prod /home/gpodder/mygpo/venv/bin/daphne --bind 192.168.1.23 --port 8080 mygpo.asgi:application

Any help would be appreciated.

mtedaldi commented 3 years ago

Could you describe, what the Issues are? Error messages? Logfiles? What do you expect to happen and what happens instead?

maxolasersquad commented 3 years ago

So at first I assumed the problem was my Nginx config. After doing a lot of reading I don't think that is the case any more.

Here is a good example of the kinds of problems that I am seeing. If I try to add a new podcast at https://podcast.baucum.me/missing/ by putting in the URL http://feeds.wnyc.org/science-friday, clicking check, and then "Add Podcast", it hangs and eventually gives me "502 Bad Gateway" error. The curl for the request looks like this, with the tokens removed.

curl 'https://podcast.baucum.me/add-podcast/' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: null' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Cookie: csrftoken=removed; sessionid=removed' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-GPC: 1' -H 'TE: Trailers' --data-raw 'csrfmiddlewaretoken=removed&url=http%3A%2F%2Ffeeds.wnyc.org%2Fscience-friday'
zoenglinghou commented 3 years ago

This is what I have after using certbot to install certificates, hope it may help:

server {

    server_name  xxx;

    # Enable HSTS (https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security)
    add_header Strict-Transport-Security "max-age=172800; includeSubdomains";

    # This checks if the certificate has been invalidated by the certificate authority
    # You can remove this section if you use self-singed certificates...
    # Enable OCSP stapling (http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox)
    ssl_stapling on;
    ssl_stapling_verify on;

    # - - - - - - - - -
    # Reverse Proxy
    # - - - - - - - - -
    proxy_redirect           off;
    proxy_set_header         X-Real-IP $remote_addr;                        # clients real IP
    proxy_set_header         X-Forwarded-For $proxy_add_x_forwarded_for;    # a proxy did forward this request
    proxy_set_header         Host $http_host;                               # Set Proxy host info

    proxy_http_version 1.1;                                                 # Required for WebSocket connection
    proxy_set_header Upgrade $http_upgrade;                                 # Allow protocol switch to websocket
    proxy_set_header Connection "upgrade";                                  # Do protocol switch
    proxy_set_header X-Forwarded-Proto $scheme;                             # this connection used HTTP or HTTPS

    client_max_body_size 500M;                                              # Bump the max body size
    proxy_buffering off;                                                    # Do not hold back the request while the client sends data, give the stream directly

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

    location /favicon.png {
        alias /var/www/mygpo/static/favicon.png;
    }

    location /media  {
        alias /var/www/mygpo/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /var/www/mygpo/static; # your Django project's static files - amend as required
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/xxx/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/xxx/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    location = /robots.txt {
    add_header Content-Type text/plain;
    return 200 "User-agent: *\nDisallow: /\n";
    }

}

server {
    if ($host = xxx) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name  xxx;

    listen 80;
    return 404; # managed by Certbot

}

Adapted it from other projects, so there are stuffs that are probably not needed.

maxolasersquad commented 3 years ago

I updated my Nginx config to be similar to what you provided here is my new config

server {
    listen 80;
    server_name podcast.xx.x;

    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-Proto $scheme;

    client_max_body_size 500M;
    proxy_buffering off;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

    location /static {
        alias /home/gpodder/mygpo/staticfiles/;

    }
    location /favicon.png {
        alias /home/gpodder/mygpo/static/favicon.png;

    }

    location /media {
        alias /home/gpodder/mygpo/media;
    }

    location = /robots.txt {
        add_header Content-Type text/plain;
        return 200 "User-agent: *\nDisallow: /\n";
    }
}

It's worth noting that the machine this is running on is not facing the Internet. I have it locked down with UFW such that it only accepts requests on port 80 from the Internet facing proxy machine.

On the proxying machine nginx looks like this.

server {
  listen 80;
  server_name podcast.xx.x;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  ssl_certificate /etc/letsencrypt/live/xx.x/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/xx.x/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/xx.x/chain.pem;
  server_name podcast.xx.x;
  proxy_set_header X-Forwarded-For $remote_addr;

  location / {
    proxy_pass http://192.168.1.23/;
    proxy_set_header Host podcast.xx.x;
  }

  access_log /var/log/nginx/gpodder_access.log;
  error_log /var/log/nginx/gpodder_error.log warn;
}

And finally here is my latest systemd configuration.

[Unit]
Description=gpodder podcast server

[Service]
Restart=on-failure
WorkingDirectory=/home/gpodder/mygpo
ExecStart=/home/gpodder/mygpo/venv/bin/envdir /home/gpodder/mygpo/envs/prod /home/gpodder/mygpo/venv/bin/gunicorn mygpo.wsgi -b 127.0.0.1:8080 --workers=2
User=gpodder
StandardOutput=append:/var/log/gpodder/gpodder.log
StandardError=append:/var/log/gpodder/error.log

[Install]
WantedBy=multi-user.target

Here is what I get in the gpodder error log.

[2021-02-17 04:21:01 +0000] [1751870] [CRITICAL] WORKER TIMEOUT (pid:1751926)
[2021-02-17 04:21:01 +0000] [1751926] [INFO] Worker exiting (pid: 1751926)
[2021-02-17 04:21:02 +0000] [1752831] [INFO] Booting worker with pid: 1752831
2021-02-17 04:21:02,401 django.request WARNING Not Found: /favicon.ico

All help is greatly appreciated.