I have many docker containers which pass through docker nginx combo (docker-compose.yml outlined below) and they work very well. I want docker nginx to do the same to a non-docker app thats running on localhost:8080, that is I want docker nginx container to run connections to example.com to 127.0.0.1:8080 where 127.0.0.1:8080 is ran by a non-docker app (code-server do be specific but that shouldn't matter)
version: '3'
services:
nginx-proxy:
image: jwilder/nginx-proxy
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- /apps/proxy/conf:/etc/nginx/conf.d
- /apps/proxy/vhost:/etc/nginx/vhost.d
- /apps/proxy/html:/usr/share/nginx/html
- /apps/proxy/dhparam:/etc/nginx/dhparam
- /apps/proxy/certs:/etc/nginx/certs:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
restart: always
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: nginx-proxy-le
depends_on:
- nginx-proxy
volumes:
- /apps/proxy/vhost:/etc/nginx/vhost.d
- /apps/proxy/html:/usr/share/nginx/html
- /apps/proxy/dhparam:/etc/nginx/dhparam:ro
- /apps/proxy/certs:/etc/nginx/certs
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- NGINX_PROXY_CONTAINER=nginx-proxy
restart: always
networks:
default:
external:
name: nginx-proxy
and its running well on docker containers, the moment i include "nginx-proxy" so that it can detect them, fantastic tool. I cant simply paste something like this into default.conf (conf of nginx )
server {
listen 80;
listen [::]:80;
server_name example.com;
location / {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
}
}
My guess is that what is "localhost" for me is not "localhost" for nginx given that it is inside a docker (im new to this docker stuff, so I might be talking shit). I saw the issue where they mentioned many approaches, none of them worked for me. In particular I tried running a dummy docker as CWempe suggested
docker run -d \
-e VIRTUAL_HOST=foo.bar.com \
-e VIRTUAL_PORT=8080 \
-e UPSTREAM_NAME=webserver.local \
--rm \
cwempe/docker-dummy:latest
This didnt't work, nginx didnt even detect it which made me think its probably because its not on the nginx-network so i added that (and turned it into docker-compose for convenience)
version: '3.3'
services:
docker-dummy:
environment:
- VIRTUAL_HOST=example.com
- VIRTUAL_PORT=8080
- UPSTREAM_NAME=127.0.0.1
image: 'cwempe/docker-dummy:latest'
networks:
default:
external:
name: nginx-proxy
Then looking at default.conf i get
# mydomain.com
upstream mydomain.com {
## Can be connected with "nginx-proxy" network
# code-server_docker-dummy_1
server 172.25.0.7 down;
}
server {
server_name mydomain.com;
listen 80 ;
access_log /var/log/nginx/access.log vhost;
include /etc/nginx/vhost.d/default;
location / {
proxy_pass http://example.com;
}
}
server {
server_name example.com;
listen 443 ssl http2 ;
access_log /var/log/nginx/access.log vhost;
return 500;
ssl_certificate /etc/nginx/certs/default.crt;
ssl_certificate_key /etc/nginx/certs/default.key;
}
So sure it has seen it but it also believes it is down and doesn't include the VIRTUAL_PORT at all and obviously the 127.25.0.7 IP doesn't make sense to me either. Changing 127.25.0.7 -> 127.0.0.1:8080 does nothing. Any idea how I can remedy this ? Thank you for your input in advance.
Related
I have a some issue when trying to deploy a simple FastAPI application with Nginx on Google Cloud Platform. In my case I should use SSH-terminal to run Docker container with Nginx and FastAPI. My nginx.conf configuration looks like:
access_log /var/log/nginx/app.log;
error_log /var/log/nginx/app.log;
server {
server_name example.com;
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /root/ssl/cert.pem;
ssl_certificate_key /root/ssl/key.pem;
location / {
proxy_pass "http://example.com:8004/";
}
}
And my docker-compose.yml looks like:
version: '3.8'
services:
nginx-proxy:
image: nginx
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx:/etc/nginx/conf.d
- ./ssl/cert1.pem:/root/ssl/cert.pem
- ./ssl/privkey1.pem:/root/ssl/key.pem
- ./ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem
web:
environment: [.env]
build: ./project
ports:
- 8004:8000
command: gunicorn main:app -k uvicorn.workers.UvicornWorker -w 2 -b 0.0.0.0:8000
volumes:
- ./project:/usr/src/app
networks:
default:
external:
name: nginx-proxy
Also, I have a Google Cloud VM instance with Firewall HTTP, HTTPS traffic On option, and additionally configured Firewall with rules allowed TCP connections over 443 and 80 ports (Domain name is provided by Google Cloud also, and redirects to VM's external IP address when I put it in my browser address field).
I run my docker-image from SSH-terminal with docker-compose up --build, then I get 502 Bad Gateway Nginx error in my browser (after going to example.com). I would like to know whether it is possible to run the docker image this way from inside SSH-terminal, as well as which steps did I miss to do it the right way?
I have a project running on docker. I use Nginx reverse proxy to run my app.
All works fine but trying to personalize the server_name on nginx but couldn't figure out how.
Docker yml file
I've added server name to /etc/hosts by docker
version: "3"
services:
nginx:
container_name: nginx
volumes:
- ./nginx/logs/nginx:/var/log/nginx
build:
context: ./nginx
dockerfile: ./Dockerfile
depends_on:
- menu-app
ports:
- "80:80"
- "433:433"
extra_hosts:
- "www.qr-menu.loc:172.18.0.100"
- "www.qr-menu.loc:127.0.0.1"
networks:
default:
ipv4_address: 172.18.0.100
menu-app:
image: menu-app
container_name: menu-app
volumes:
- './menu-app/config:/var/www/config'
- './menu-app/core:/var/www/core'
- './menu-app/ecosystem.json:/var/www/ecosystem.json'
- './menu-app/tsconfig.json:/var/www/tsconfig.json'
- './menu-app/tsconfig-build.json:/var/www/tsconfig-build.json'
- "./menu-app/src:/var/www/src"
- "./menu-app/package.json:/var/www/package.json"
build:
context: .
dockerfile: menu-app/.docker/Dockerfile
tmpfs:
- /var/www/dist
ports:
- "3000:3000"
extra_hosts:
- "www.qr-menu.loc:127.0.0.1"
- "www.qr-menu.loc:172.18.0.100"
networks:
default:
ipam:
driver: default
config:
- subnet: 172.18.0.0/24
And I have Nginx conf
server_names_hash_bucket_size 1024;
upstream local_pwa {
server menu-app:3000;
keepalive 8;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name www.qr-menu.loc 172.18.0.100;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://local_pwa/;
}
}
but unfortunately, app runs on localhost instead of www.qr-menu.loc
I couldn't figure out how to change server_name on Nginx.
This is a really, really late answer. The server_name directive tells nginx which configuration block to use on receipt of a request. Also see: http://nginx.org/en/docs/http/server_names.html
I think the docker-compose extra_hosts directive might only work for domain-name resolution within the docker network. In other words, on your computer that's running docker the name "www.qr-menu.loc" is not available, but in a running docker container that name should be available.
I have a docker-compose.yml as follows setup at my root. For context, I have a Ghost CMS blog hosted on a Digital Ocean droplet. I want to install Commento using Docker (an open source commenting solution), but as I'm routing my traffic through Cloudflare DNS, I require SSL on both the server side and the frontend side.
However, I installed Ghost through Digital Ocean's one click Ghost setup, which configured nginx to be the reverse proxy for my site. Nginx is NOT in the container (installed on server). Nginx listens on port 80 and 443. When I try docker-compose up, it says the following error:
Error starting userland proxy: listen tcp 0.0.0.0:443: bind: address already in use
Traefik cannot listen on the same ports at nginx (which is not within the container, but installed on the server itself). How can I fix this problem, and have my commento server reverse proxied through SSL as well? My docker-compose is as below:
version: '3.7'
services:
proxy:
restart: always
image: traefik
command:
- "--api"
- "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
- "--entrypoints=Name:https Address::443 TLS"
- "--defaultentrypoints=http,https"
- "--acme"
- "--acme.storage=/etc/traefik/acme/acme.json"
- "--acme.entryPoint=https"
- "--acme.httpChallenge.entryPoint=http"
- "--acme.onHostRule=true"
- "--acme.onDemand=false"
- "--acme.email=changeme#example.com" # TODO: Replace with your email address
- "--docker"
- "--docker.watch"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/acme:/etc/traefik/acme
networks:
- web
ports:
- "80:80"
- "443:443"
labels:
- "traefik.enable=false"
server:
image: registry.gitlab.com/commento/commento:latest
ports:
- 8080:8080
environment:
COMMENTO_ORIGIN: https://commento.example.com # TODO: Replace commento.example.com with your domami$ COMMENTO_PORT: 8080
COMMENTO_POSTGRES: postgres://postgres:passwordexample#db:5432/commento?s$
depends_on:
- db
networks:
- db_network
- web
db:
image: postgres
environment:
POSTGRES_DB: commento
POSTGRES_USER: postgres
POSTGRES_PASSWORD: examplepassword #TODO: Replace STRONG_PASSWORD with th$ networks:
- db_network
volumes:
- postgres_data_volume:/var/lib/postgresql/data
volumes:
postgres_data_volume:
networks:
web:
external
db_network:
Here is my nginx server config under available sites:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
root /var/www/ghost/system/nginx-root; # Used for acme.sh SSL verification (https://acme.sh)
ssl_certificate /etc/letsencrypt/example.com/fullchain.cer;
ssl_certificate_key /etc/letsencrypt/example.com/example.com.key;
include /etc/nginx/snippets/ssl-params.conf;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:2368;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
Sorry, kind of new to this. Thank you!
docker-compose.yml
...
ports:
- "80:80"
- "443:443"
...
nginx/conf
...
listen 443 ssl http2;
listen [::]:443 ssl http2;
...
Nginx used HOST port 443, so you cannot reuse it on your docker-compose, you must another one that is free.
I am trying to find a way to publish nginx, express, and letsencrypt's ssl all together using docker-compose. There are many documents about this, so I referenced these and tried to make my own configuration, I succeed to configure nginx + ssl from this https://medium.com/#pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71
So now I want to put sample nodejs express app into nginx + ssl docker-compose. But I don't know why, I get 502 Bad Gateway from nginx rather than express's initial page.
I am testing this app with my left domain, and on aws ec2 ubuntu16. I think there is no problem about domain dns and security rules settings. All of 80, 443, 3000 ports opened already. and When I tested it without express app it shows well nginx default page.
nginx conf in /etc/nginx/conf.d
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
server_tokens off;
location / {
proxy_pass http://localhost: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;
}
ssl_certificate /etc/letsencrypt/live/sendpi.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sendpi.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
docker-compose.yml
version: '3'
services:
app:
container_name: express
restart: always
build: .
ports:
- '3000:3000'
nginx:
container_name: nginx
image: nginx:1.15-alpine
restart: unless-stopped
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- "80:80"
- "443:443"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Dockerfile of express
FROM node:12.2-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
I think SSL works fine, but there are some problems between express app and nginx. How can I fix this?
proxy_pass http://localhost:3000
is proxying the request to the 3000 port on the container that is running nginx. What you instead want is to connect to the 3000 port of the container running express. For that, we need to do two things.
First, we make the express container visible to nginx container at a predefined hostname. We can use links in docker-compose.
nginx:
links:
- "app:expressapp"
Alternatively, since links are now considered a legacy feature, a better way is to use a user defined network. Define a network of your own with
docker network create my-network
and then connect your containers to that network in compose file by adding the following at the top level:
networks:
default:
external:
name: my-network
All the services connected to a user defined network can access each other via name without explicitly setting up links.
Then in the nginx.conf, we proxy to the express container using that hostname:
location / {
proxy_pass http://app:3000
}
Warning: The --link flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it, we recommend that you use user-defined networks to facilitate communication between two containers instead of using --link.
Define networks in your docker-compose.yml and configure your services with the appropriate network:
version: '3'
services:
app:
restart: always
build: .
networks:
- backend
expose:
- "3000"
nginx:
image: nginx:1.15-alpine
restart: unless-stopped
depends_on:
- app
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
networks:
- frontend
- backend
ports:
- "80:80"
- "443:443"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
networks:
frontend:
backend:
Note: the app service no longer publish's it's ports to the host it only exposes port 3000 (ref. exposing and publishing ports), it is only available to services connected to the backend network. The nginx service has a foot in both the backend and frontend network to accept incoming traffic from the frontend and proxy the connections to the app in the backend (ref. multi-host networking).
With user-defined networks you can resolve the service name:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream app {
server app:3000 max_fails=3;
}
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
server_tokens off;
location / {
proxy_pass http://app;
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;
}
ssl_certificate /etc/letsencrypt/live/sendpi.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sendpi.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
}
Removing the container_name from your services makes it possible to scale the services: docker-compose up -d --scale nginx=1 app=3 - nginx will load balance the traffic in round-robin to the 3 app containers.
I think maybe a source of confusion here is the way the "localhost" designation behaves among running services in docker-compose. The way docker-compose orchestrates your containers, each of the containers understands itself to be "localhost", so "localhost" does not refer to the host machine (and if I'm not mistaken, there is no way for a container running on the host to access a service exposed on a host port, apart from maybe some security exploits). To demonstrate:
services:
app:
container_name: express
restart: always
build: .
ports:
- '2999:3000' # expose app's port on host's 2999
Rebuild
docker-compose build
docker-compose up
Tell container running the express app to curl against its own running service on port 3000:
$ docker-compose exec app /bin/bash -c "curl http://localhost:3000"
<!DOCTYPE html>
<html>
<head>
<title>Express</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1>Express</h1>
<p>Welcome to Express</p>
</body>
</html>
Tell app to try to that same service which we exposed on port 2999 on the host machine:
$ docker-compose exec app /bin/bash -c "curl http://localhost:2999"
curl: (7) Failed to connect to localhost port 2999: Connection refused
We will of course see this same behavior between running containers as well, so in your setup nginx was trying to proxy it's own service running on localhost:3000 (but there wasn't one, as you know).
Tasks
build NodeJS app
add SSL functionality from the box (that can work automatically)
Solution
https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion
/ {path_to_the_project} /Docker-compose.yml
version: '3.7'
services:
nginx-proxy:
image: jwilder/nginx-proxy:alpine
restart: always
container_name: nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
ports:
- "443:443"
- "80:80"
labels:
- "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: letsencrypt
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
- ./vhost.d:/etc/nginx/vhost.d:rw
- ./html:/usr/share/nginx/html:rw
environment:
- NGINX_PROXY_CONTAINER=nginx-proxy
api:
container_name: ${APP_NAME}
build:
context: .
dockerfile: Dockerfile
command: npm start --port ${APP_PORT}
expose:
- ${APP_PORT}
# ports:
# - ${APP_PORT}:${APP_PORT}
restart: always
environment:
VIRTUAL_PORT: ${APP_PORT}
VIRTUAL_HOST: ${DOMAIN}
LETSENCRYPT_HOST: ${DOMAIN}
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
NODE_ENV: production
PORT: ${APP_PORT}
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
/ {path_to_the_project} /.env
APP_NAME=best_api
APP_PORT=3000
DOMAIN=api.site.com
LETSENCRYPT_EMAIL=myemail#gmail.com
Do not forget to connect DOMAIN to you server before you will run container there.
How it works?
just run docker-compose up --build -d
I have a docker with 2 containers for serving individual sites and jwilder/nginx-proxy in front of them.
However I'm only getting the default nginx page, so the vhosts aren't routing correctlty.
I've used https://www.rent-a-hero.de/wp/2017/06/09/use-j-wilders-nginx-proxy-for-multiple-docker-compose-projects/ as a guide t get myself started on this, because I wanted to set up a proxy network.
Each of the serving nxinx containers has a vhost file, and uses a 4th, shared php container (the code is the same in both nginx containers).
$ docker run -d \
--name nginx-proxy \
-p 80:80 \
--network=nginx-proxy \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
jwilder/nginx-proxy
/docker-compose.yml
version: '2'
services:
app-admin:
image: nginx:latest
container_name: app-admin
environment:
VIRTUAL_HOST: admin.app.local
VIRTUAL_PORT: 80
volumes:
- .:/var/www/html
- admin.app.conf:/etc/nginx/vhost.d/admin.app.local:ro
links:
- php
php:
image: php:7-fpm
container_name: php
volumes:
- .:/var/www/html
networks:
default:
external:
name: nginx-proxy
/admin.app.conf:
server {
server_name admin.app.local
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.php;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ /\.ht {
deny all;
}
}
app.conf is essentially the same for this testing stage... same result
Original files edited to help simplify the question (the removed files just basically setup the required nginx-proxy container and network, and I;ve stripped out the example second nginx container)