Cannot Retrieve OAuth Client Credentials - FreeBSD

Hello!,

I am following along with the production guide to set up a personal instance of peertube on a FreeBSD 11.1 jail. The first half of the guide went very well, but at the point where nginx is configured I got a little lost.

My changes:

  • The version of nginx on FreeBSD 11.1 does not have a sites-enabled/ directory, so I took the default peertube config (/var/www/peertube/peertube-latest/support/nginx/peertube) and replaced the default server{} block in nginx.conf (/usr/local/etc/nginx/nginx.conf)
  • I followed a guide (techtalk.blog/simple-and-free-ssl-certificates-using-letsencrypt-and-nginx-530f03aee07) to install a letsencrypt certificate with dehydrate.
  • After the installation was finished, all I could get was error 502 “Bad Gateway” when I browsed to the site. So I changed the https port to 9008 in order to not have to use an nginx reverse proxy in front of the peertube machine. Then I forwarded that port directly from the router. That seems to work.

I can now access the site, but cannot log in with the root account and password in peertube.log. There is also a warning that flashes on page load about OAuth. I saw a similar thread (framacolibri .org/t/not-finding-admin-username-and-having-problem-with-nginx/3151/4) here and read it, but was unable to solve the problem from the posts there.

production.yaml:

listen:
  hostname: 'localhost'
  port: 9000

# Correspond to your reverse proxy "listen" configuration
webserver:
  https: true
  hostname: 'localhost'
  #port: 443
  port: 9008

# Proxies to trust to get real client IP
# If you run PeerTube just behind a local proxy (nginx), keep 'loopback'
# If you run PeerTube behind a remote proxy, add the proxy IP address (or subnet)
trust_proxy:
  - 'loopback'

# Your database name will be "peertube"+database.suffix
database:
  hostname: 'localhost'
  port: 5432
  suffix: '_prod'
  username: 'peertube'
  password: 'XXXX'

...

nginx.conf:

#user  nobody;
worker_processes  1;

# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info. 
#
#error_log  /var/log/nginx/error.log;
#

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
          listen 80;
          listen [::]:80;
          server_name video.csb.sh;
        
          access_log /var/log/nginx/peertube.access.log;
          error_log /var/log/nginx/peertube.error.log;
        
          #location /.well-known/acme-challenge/ {
          #  default_type "text/plain";
          #  root /usr/local/var/www/certbot;
          #}
          
        # Redirect LetsEncrypt to dehydrated
        location ^~ /.well-known/acme-challenge {
        auth_basic "off";
        alias /usr/local/www/dehydrated;
        }
          #location / { return 301 https://$host$request_uri; }
          location / { 
#                 return 301 https://$host$request_uri; 
            root   /usr/local/www/nginx;
            index  index.html index.htm;
          }
        }
        
        server {
          listen 9008 ssl http2;
          listen [::]:9008 ssl http2;
          server_name video.csb.sh;
        
          # For example with certbot (you need a certificate to run https)
          ssl_certificate      /usr/local/etc/dehydrated/certs/video.csb.sh/fullchain.pem;
          ssl_certificate_key  /usr/local/etc/dehydrated/certs/video.csb.sh/privkey.pem;
        
          # Security hardening (as of 11/02/2018)
          ssl_protocols TLSv1.2; # TLSv1.3, TLSv1.2 if nginx >= 1.13.0
          ssl_prefer_server_ciphers on;
          ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
          # ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0, not compatible with import-videos script
          ssl_session_timeout  10m;
          ssl_session_cache shared:SSL:10m;
          ssl_session_tickets off; # Requires nginx >= 1.5.9
          ssl_stapling on; # Requires nginx >= 1.3.7
          ssl_stapling_verify on; # Requires nginx => 1.3.7
        
          # Configure with your resolvers
          # resolver $DNS-IP-1 $DNS-IP-2 valid=300s;
          # resolver_timeout 5s;
        
          add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
          add_header X-Content-Type-Options nosniff;
          add_header X-XSS-Protection "1; mode=block";
          add_header X-Robots-Tag none;
          
          access_log /var/log/nginx/peertube.access.log;
          error_log /var/log/nginx/peertube.error.log;
        
          #location ^~ '/.well-known/acme-challenge' {
          #  default_type "text/plain";
          #  root /usr/local/var/www/certbot;
          #}
          
        # Redirect LetsEncrypt to dehydrated
        location ^~ /.well-known/acme-challenge {
        auth_basic "off";
        alias /usr/local/www/dehydrated;
        }
        
          location ~ ^/client/(.*\.(js|css|woff2|otf|ttf|woff|eot))$ {
            add_header Cache-Control "public, max-age=31536000, immutable";
        
            alias /var/www/peertube/peertube-latest/client/dist/$1;
          }
        
          location ~ ^/static/(thumbnails|avatars)/(.*)$ {
            add_header Cache-Control "public, max-age=31536000, immutable";
        
            alias /var/www/peertube/storage/$1/$2;
          }
        
          location / {
            proxy_pass http://localhost:9000;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
            # Hard limit, PeerTube does not support videos > 4GB
            client_max_body_size 4G;
            proxy_connect_timeout       600;
            proxy_send_timeout          600;
            proxy_read_timeout          600;
            send_timeout                600;
          }

        
          # Bypass PeerTube webseed route for better performances
          location /static/webseed {
            # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client
            limit_rate 800k;
        
            if ($request_method = 'OPTIONS') {
              add_header 'Access-Control-Allow-Origin' '*';
              add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
              add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
              add_header 'Access-Control-Max-Age' 1728000;
              add_header 'Content-Type' 'text/plain charset=UTF-8';
              add_header 'Content-Length' 0;
              return 204;
            }
        
            if ($request_method = 'GET') {
              add_header 'Access-Control-Allow-Origin' '*';
              add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
              add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
        
              # Don't spam access log file with byte range requests
              access_log off;
            }
        
            alias /var/www/peertube/storage/videos;
          }
        
          # Websocket tracker
          location /tracker/socket {
            # Peers send a message to the tracker every 15 minutes
            # Don't close the websocket before this time
            proxy_read_timeout 1200s;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_http_version 1.1;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_pass http://localhost:9000;
          }
        }
}

I’m sure that I have just missed something obvious in setting up the server, and I appreciate any troubleshooting advice you can give me.

Thanks!

** I’ve edited down some links as new users can only include two links :-/

Hi,

have you look at :

Here is my nginx working conf for Peertube, note that the fqdn of the instance is peertube.gegeweb.eu and the network jail is on a cloned interface lo1 with ip 10.0.0.2.
Everything in the same jail for my conf.

In /usr/local/etc/nginx.conf:

include	nginx-include.conf;

Then, in /usr/local/etc/nginx-include.conf :

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name peertube.gegeweb.eu;

  access_log /var/log/nginx/peertube.gegeweb.eu.access.log;
  error_log /var/log/nginx/peertube.gegeweb.eu.error.log;

  # Redirect LetsEncrypt to dehydrated
  location ^~ /.well-known/acme-challenge {
    auth_basic "off";
    alias /usr/local/www/dehydrated;
  }

  location / { return 301 https://peertube.gegeweb.eu$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name peertube.gegeweb.eu;

  # For example with certbot (you need a certificate to run https)
  ssl_certificate         /usr/local/etc/dehydrated/certs/peertube.gegeweb.eu/fullchain.pem;
  ssl_certificate_key     /usr/local/etc/dehydrated/certs/peertube.gegeweb.eu/privkey.pem;
  ssl_dhparam             /usr/local/etc/dehydrated/certs/dhparam.pem;	

  # Security hardening (as of 11/02/2018)
  ssl_protocols TLSv1.2; # TLSv1.3, TLSv1.2 if nginx >= 1.13.0
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
  # ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0, not compatible with import-videos script
  ssl_session_timeout  10m;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off; # Requires nginx >= 1.5.9
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 10.0.0.254 valid=300s;
  resolver_timeout 10s;

  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Robots-Tag none;
  
  access_log /var/log/nginx/peertube.gegeweb.eu.access.log;
  error_log /var/log/nginx/peertube.gegeweb.eu.error.log;

  # Redirect LetsEncrypt to dehydrated
  location ^~ /.well-known/acme-challenge {
    auth_basic "off";
    alias /usr/local/www/dehydrated;
  }

  location ~ ^/client/(.*\.(js|css|woff2|otf|ttf|woff|eot))$ {
    add_header Cache-Control "public, max-age=31536000, immutable";

    alias /var/www/peertube/peertube-latest/client/dist/$1;
  }

  location ~ ^/static/(thumbnails|avatars)/(.*)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";

    alias /var/www/peertube/storage/$1/$2;
  }

  location / {
    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 https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://10.0.0.200:9000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # Hard limit, PeerTube does not support videos > 4GB
    client_max_body_size 4G;
    proxy_connect_timeout       600;
    proxy_send_timeout          600;
    proxy_read_timeout          600;
    send_timeout                600;
  }

  # Bypass PeerTube webseed route for better performances
  location /static/webseed {
    # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client
    limit_rate 800k;

    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Content-Length' 0;
      return 204;
    }

    if ($request_method = 'GET') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

      # Don't spam access log file with byte range requests
      access_log off;
    }

    alias /var/www/peertube/storage/videos;
  }

  # Websocket tracker
  location /tracker/socket {
    # Peers send a message to the tracker every 15 minutes
    # Don't close the websocket before this time
    proxy_read_timeout 1200s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_pass http://10.0.0.200:9000;
  }
}
[root

In /var/www/peertube/config/production.yaml:

listen:
  hostname: '10.0.0.200'
  port: 9000

# Correspond to your reverse proxy "listen" configuration => IMPORTANT : not the fqdn host for the local machine.
webserver:
  https: true
  hostname: 'peertube.gegeweb.eu'
  port: 443

# Proxies to trust to get real client IP
# If you run PeerTube just behind a local proxy (nginx), keep 'loopback'
# If you run PeerTube behind a remote proxy, add the proxy IP address (or subnet)
trust_proxy:
  - '10.0.0.200'

# Your database name will be "peertube"+database.suffix
database:
  hostname: '10.0.0.200'
  port: 5432
  suffix: '_prod'
  username: 'peertube'
  password: 'peertube'

redis:
  hostname: '10.0.0.200'
  port: 6379
  auth: null
  db: 0

----><----

Is the rc script installed in /usr/local/etc/rc.dwith the executable bit? And service launched ?

Everithing works fine for me with this conf. I’ve write the doc after testing my installation! :wink:

1 « J'aime »

I had not seen that page, thank you! And thanks also for the sample configuration!

I have the site working now, but want to revisit the HTTPS situation at some point, since I’d prefer to have https from the outer proxy machine to the peertube one as well.

I also didn’t move the port 9000 server block to my outer proxy, is there a reason I should consider doing so?

Then I think this is exactly the situation described in the Wiki documentation.
The proxy is on a different host (jail) than the Peertube service host.
If needed the author is @Lovis_IX@mastodon.tamanoir.foucry.net on Mastodon.

For my part the nginx proxy is on the same host as Peertube.