I’ve got an API (Laravel) and a UI (Next.js SSR) being served via nginx using Docker. From the client side everything is working as intended, I’m able to hit the pages and call the API without issues. However, when I try leveraging the server side aspect of Next.js for data fetching it fails.
The following is my docker-compose.yaml
:
name: my-app
networks:
mynetwork:
driver: bridge
services:
nginx:
container_name: nginx
build:
context: ./nginx
target: dev
ports:
- '80:80'
- '443:443'
networks:
- mynetwork
depends_on:
- api
- app
app:
container_name: app
build:
context: ./app
target: dev
volumes:
- ./app:/app
networks:
- mynetwork
depends_on:
- api
api:
container_name: api
build:
context: ./api
target: dev
volumes:
- ./api:/var/www
networks:
- mynetwork
I then have the following server blocks setup for my nginx configuration:
server {
server_name myapp.localhost;
location / {
proxy_pass http://app:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
server {
server_name api.myapp.localhost;
root /var/www/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
client_max_body_size 50M;
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; }
error_page 404 /index.php;
location ~ .php$ {
fastcgi_pass api:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /.(?!well-known).* {
deny all;
}
}
Now the problem code, in my app/layout.tsx
:
export default async function Layout({children}: DefaultProps): Promise<ReactNode> {
const session = await fetch();
return (
<html lang="en">
<head>
<meta charSet="utf-8"/>
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<link
rel="icon"
type="image/ico"
href="/img/favicon/favicon.ico"
/>
</head>
<body>
<UserProvider session={session}>
<Header/>
<main>
<AuthModal/>
{children}
</main>
<Footer/>
</UserProvider>
</body>
</html>
);
}
Where the fetch()
call is a GET
request hitting http://api.myapp.localhost/...
but Next.js responds with an error:
Unhandled Runtime Error
Error: connect ECONNREFUSED 127.0.0.1:80
I presume this is because the container itself doesn’t know the hostname being referenced because that’s handled by host machine and nginx handles the routing via the server names.
I can’t directly pass the container name as part of the API endpoint request because the API is using fpm so it needs nginx.
I’ve tested this by transforming the server side call to an client side call and it works without issue and I couldn’t find other questions which would point me in the right direction to solve this.
What’s the fix?
2