Background:
I'm currently trying to fetch data from an endpoint from a next.js application. The backend is a simple Flask app (in development mode) with an exposed port at 5000. Nginx is acting as a reverse proxy for next and flask, as well as handling http -> https. I'm using docker compose to bring all these services together. I'm hosting all of these services on a single droplet on DigitalOcean.
I've gone through multiple iterations since going from a local dev environment (i.e. just using localhost) to deployment (https website). The errors range from 404, net::ERR_SSL_PROTOCOL_ERROR, to mixed content errors (depending on the iteration). Despite the range of errors, there is clearly something fundamental I'm missing here that's preventing fetch from working.
Code:
NGINX
server {
listen 80;
server_name mydomainname.com;
location / {
return 301 https://$host$request_uri;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
# https traffic
server {
listen 443 ssl;
server_name mydomainname.com;
add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
ssl_certificate /etc/letsencrypt/live/mydomainname.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomainname.com/privkey.pem;
location / {
proxy_pass http://client:3000;
proxy_redirect default;
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-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://api:5000;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
DOCKER
version: '3.7'
services:
api:
container_name: api
build:
context: ./api
dockerfile: Dockerfile
volumes:
- './api:/usr/src/app'
ports:
- 5000:5000
environment:
- FLASK_CONFIG=development
- FLASK_ENV=development
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
restart: unless-stopped
ports:
- 80:80
- 443:443
depends_on:
- api
- client
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
certbot:
image: certbot/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
client:
container_name: client
build:
context: ./client
dockerfile: Dockerfile
volumes:
- './client:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- 3000:3000
environment:
- NODE_ENV=development
- REACT_APP_SERVICE_URL=http://localhost:8080
- CHOKIDAR_USEPOLLING=true
depends_on:
- api
FLASK
@app.route('/myroute', methods=['GET'])
def my_route():
keywords = request.args.getlist('search')
# TRUNCATED CODE STARTS HERE THAT FORMS JSON DATA
# ...
# ...
response = flask.jsonify(json)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
if __name__ == '__main__':
app.run(port='5000')
NEXT
const fetchData = async () => {
const response = await fetch(`https:mydomainname.com/api/myroute?search=${search}`)
const json: ApiResponse = await response.json()
}
// call the function
fetchData().catch(res => {
console.log(res)
router.push(`/`)
});
}
I've truncated the next and flask code so it's easier to parse.
In terms of a (short) list of things I've tried in terms of url formation in fetch:
fetch(`https:mydomainname.com/api/myroute?search=${search}`)
fetch(`http:mydomainname.com/api/myroute?search=${search}`)
fetch(`http:mydomainname.com/myroute?search=${search}`)
fetch(`https:mydomainname.com/myroute?search=${search}`)
fetch(`//mydomainname.com/myroute?search=${search}`)