0

My goal is to build a contact form for a static website (pure html/css/js). It's on a server using Nginx which serves a single index.html file. index.html includes a Javascript file that is called when the contact form is submitted. This JS file awaits axios to make a POST request to localhost:3000/contact, which is a NodeJS app that I wrote running on that port, and sends the e-mail using nodemailer.

When I submit the contact form on my local computer, everything works fine (I receive an email). But when I try it on my server using Nginx, it fails. I receive the error: 405 not allowed. It also looks like the server function is never called.

My first question is: is this even possible using Nginx?

If so, then what does my config file need to look like? Here is the base file:

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

server {
        listen 443 ssl;
        server_name www.website.com;

        ssl_certificate /etc/nginx/ssl/website-com-cert.pem;
        ssl_certificate_key /etc/nginx/ssl/website-com-key.pem;

        location / {
                root /var/www/html;
                index index.html index.htm;
        }
}

I've tried every suggestion from this question and none of them have worked. Setting 405 = 200 removes the error message but the NodeJS server never gets the function call to send the email (if it did, that would work for me). Or the other suggestions will show an error "Cannot POST /" or "Cannot POST /index.html" on a blank screen when the contact form submits. It just gets worse from there.

Most questions involving NodeJS servers on Nginx assume that the whole thing is a singular app, so they make it a reverse proxy to localhost:port or something. But I want to serve index.html as a static file, which then makes a POST request to an app running on a port on the same server.

I can't believe that a contact form for a static site is this difficult to code. What could I be doing wrong? Is this even possible? Am I going about this completely the wrong way? I don't really NEED it to use Nginx specifically, but how else will I serve the static file? And I don't want to use a third-party forms SaaS that "does the work for me" -- it needs to be done myself.

Kinjo
  • 43
  • 1
  • 7

1 Answers1

-1

Here is the answer, which I found out after going to bed and searching more after waking up:

First, you don't need the axios step. Change the contact form like so:

<form id="contact-form" method="post" action="https://website.com/api/contact">
</form>

Assuming your server runs on port 3000, the Nginx file will look like this: (source)

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

server {
        listen 443 ssl;
        server_name www.website.com;

        ssl_certificate /etc/nginx/ssl/website-com-cert.pem;
        ssl_certificate_key /etc/nginx/ssl/website-com-key.pem;


        root /var/www/html;
        index index.html index.htm;

        location /api {

        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;

        proxy_pass http://localhost:3000;
        }
}

Then you use express to handle a POST request on /api/contact/: (be sure to use bodyparser, or else you won't receive any fields)

const app = express()
const PORT = process.env.PORT || 3000;
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({limit: '5000mb', extended: true, parameterLimit: 100000000000}));

app.post('/api/contact', [ 

], async (req, res) => {

    // not sure if these are necessary?
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT, GET,POST");

    console.log("Made it to function");
    const message = req.body.email + "\n\n" + req.body.name +"\n\n" + req.body.message;
    res.send('Thanks for submitting');

});

So what happens is when you submit the form, it goes to api/contact, which Nginx knows to proxy to port 3000, which then handles the functionality. You can then change the "thanks" message to a full HTML page to make it look nicer and provide a way to return to the original page.

That said, all of this is completely useless if your VPS provider won't open the port to send emails through, so in the end it's easier to use Netlify which accomplishes all of these things in a matter of seconds (and it's free compared to the VPS).

Kinjo
  • 43
  • 1
  • 7