Search code examples
nginxsslpanelnginx-reverse-proxy

Pterodactyl panel nginx webserver configuration for another port


I'm new to nginx, I want to make this nginx webserver configuration which is for pterodactyl panel run on port 8080 instead of 80

This is my current code

server_tokens off;

server {
    listen 80;
    server_name mywebsite.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name mywebsite.com;

    root /var/www/pterodactyl/public;
    index index.php;

    access_log /var/log/nginx/pterodactyl.app-access.log;
    error_log  /var/log/nginx/pterodactyl.app-error.log error;

    # allow larger file uploads and longer script runtimes
    client_max_body_size 100m;
    client_body_timeout 120s;

    sendfile off;

    ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
    ssl_prefer_server_ciphers on;

    # See https://hstspreload.org/ before uncommenting the line below.
    # add_header Strict-Transport-Security "max-age=15768000; preload;";
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header Content-Security-Policy "frame-ancestors 'self'";
    add_header X-Frame-Options DENY;
    add_header Referrer-Policy same-origin;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTP_PROXY "";
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
        include /etc/nginx/fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

I tried to do

server {
    listen 8080;
    server_name mywebsite.com;
    return 301 https://$server_name$request_uri;
}

but it gives ERR_SSL_PROTOCOL_ERROR when I use port 8080, port 80 still works even though I changed port 80 to port 8080 It works fine when I use this HTTP configuration (without SSL) instead of HTTPS (with SSL)

server {
    listen 8080;
    server_name mywebsite.com;


    root /var/www/pterodactyl/public;
    index index.html index.htm index.php;
    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/pterodactyl.app-error.log error;

    # allow larger file uploads and longer script runtimes
    client_max_body_size 100m;
    client_body_timeout 120s;

    sendfile off;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTP_PROXY "";
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }

    location ~ /\.ht {
        deny all;
    }
}

Solution

  • tldr: change listen 443 ssl http2; to listen 8080 ssl http2; and then connect with something like https://localhost:8080

    So some quick background to help.

    Nginx in your default config is listening on two ports, 80 and 443, and it's speaking a different protocol on each. On port 80 its speaking plain HTTP. On port 443, it's speaking HTTPS, which is plain HTTP wrapped up in encryption using the SSL/TLS protocol (this is an oversimplification and I realize it's not fully technically accurate, but it's good enough for this discussion). If you try to talk vanilla HTTP to a HTTPS port, the server won't understand, it's like ordering a drink in Greek to a Korean bartender--it will cause confusion.

    So when you connect to a website, you need to specify the protocol, the server, and the port (and a bunch of other things that are beside the point for this discussion). So connecting to http://servername:8080 would be

    • Protocol: http
    • server: servername
    • Port: 8080

    But people hate typing numbers[citation needed], so we have a convention. If you connect to a server with http and don't specify a port number, your browser (or whatever your HTTP client is) defaults to port 80. If you connect to a server with https, your http client with connect to port 443. So essentially https://google.com is translated to https://google.com:443.

    But if we're using non-standard ports (i.e. not 80 or 443), then we have to make sure the protocol matches what the server is serving. By loose convention we tend to use 8080 for an alternative HTTP port and 8443 for an alternative HTTPS port--there's nothing that forces you to do this, it just helps reduce some confusion to humans looking at the port number.

    So your nginx config is listening on two ports. listen 80; tells it that the first block is configuring a web server that is accessible on port 80 and is speaking plain HTTP (we know it's plain HTTP because that's the default for nginx and there's no additional parameters on the listen line.

    listen 443 ssl http2; tells nginx that this server block is controlling a web server that is accessible on port 443 and speaks HTTPS (because of the ssl parameter. We're going to politely ignore http2 for now as it's a non-sequitur here).

    So when you have a block with listen 8080, your server will be accessible by http://mywebsite.com:8080. However, that block in your config doesn't actually serve any content. It has the line return 301 https://$server_name$request_uri; which says whenever it receives a request to this port it will always reply with an HTTP 301 message which is a redirect telling the client that the content they're looking for is actually on https, so the client (your browser) receives this and then it reconnects to the same address but using https, so when you connect to http://mywebsite.com:8080/login your browser will be redirected to https://mywebsite.com/login.

    So if you want to access your content over port 8080, then you'd need to either:

    • serve the entire web site unencrypted by replacing that redirect line with all of your content configuration, then you could access it at http://mywebsite.com:8080 (I don't advise this), OR
    • have the https listener listen on 8080, so that you can access it at https://mywebsite.com:8080

    The latter configuration would look something like this (I haven't tested this). This only changes the redirect in the first server block so that anyone that connects to http://mywebsite.com is redirected to https://mywebsite.com:8080 and the listen port in the HTTPS block.

    server_tokens off;
    
    server {
        listen 80;
        server_name mywebsite.com;
        return 301 https://$server_name:8080$request_uri;
    }
    
    server {
        listen 8080 ssl http2;
        server_name mywebsite.com;
    
        root /var/www/pterodactyl/public;
        index index.php;
    
        access_log /var/log/nginx/pterodactyl.app-access.log;
        error_log  /var/log/nginx/pterodactyl.app-error.log error;
    
        # allow larger file uploads and longer script runtimes
        client_max_body_size 100m;
        client_body_timeout 120s;
    
        sendfile off;
    
        ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
        ssl_session_cache shared:SSL:10m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
        ssl_prefer_server_ciphers on;
    
        # See https://hstspreload.org/ before uncommenting the line below.
        # add_header Strict-Transport-Security "max-age=15768000; preload;";
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header Content-Security-Policy "frame-ancestors 'self'";
        add_header X-Frame-Options DENY;
        add_header Referrer-Policy same-origin;
    
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }
    
        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/run/php/php8.1-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param HTTP_PROXY "";
            fastcgi_intercept_errors off;
            fastcgi_buffer_size 16k;
            fastcgi_buffers 4 16k;
            fastcgi_connect_timeout 300;
            fastcgi_send_timeout 300;
            fastcgi_read_timeout 300;
            include /etc/nginx/fastcgi_params;
        }
    
        location ~ /\.ht {
            deny all;
        }
    }