docker-compose: nginx container proxy to couchdb container - docker

Trying to put together a compose setup using an nginx proxy to couchdb.
I can get this to work swimmingly well in a VM environment, but I can't get it to work in docker - with curl on the host to localhost:8085, I get '(52) Empty reply from server'. Nothing is showing up in the log output, nor is anything showing in the nginx access/error logs in the container.
Here is my docker-compose file:
version: "3"
services:
db.list-2-list:
container_name: db.list-2-list.lcldev
build: ./db.list-2-list/dev
ports:
- "8085:80"
networks:
- backend
- frontend
volumes:
- ./db.list-2-list/dev/conf.d:/etc/nginx/conf.d
couchdb:
container_name: "aph-couchdb"
image: "aph/couchdb"
networks:
- backend
volumes:
- cb-combined:/opt/couchdb/data
networks:
backend:
frontend:
volumes:
cb-combined:
external:
name: "cb-combined"
The 'aph-coucdb' container is derived from the apache couchdb image - It just contains my local.ini file (substituting the apache couchdb image with default config shows the same results.)
Port 5984 is exposed in the base image, so I'm not exposing it here (although I have tried that.) If I add a ports entry to the couchdb service exporting 5984:5984, then I can talk to the couchdb container directly, and all seems fine with it. I can also exec into the nginx container, and ping/curl aph-couchdb with expected results.
Here's my nginx config:
server {
listen 80 default;
# listen [::]:80;
location / {
proxy_pass aph-couchdb:5984;
proxy_redirect off;
# 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_hide_header X-Powered-By;
if ($request_method = OPTIONS ) {
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, HEAD, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'X-Auth-CouchDB-UserName,X-Auth-CouchDB-Roles,X-Auth-CouchDB-Token,Accept,Authorization,Origin,Referer,X-Csrf-Token,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
location ~ ^/(.*)/_changes {
proxy_pass aph-couchdb:5984;
}
}
The commented out entries are various things I've tried based on other research - none make a difference - I still get the (52) Empty reply from server when I curl localhost:8085 from the host.
Can't seem to get any further on this...
Thoughts appreciated.
rickb

Related

502 connection refuse while sending requests from docker-compose

I have a golang application that works well locally (I send requests and get the correct responses). But when I try to run this application in containers with nginx proxy server, I get a 502 error for all requests:
[error] 31#31: *1 connect() failed (111: Connection refused) while
connecting to upstream, client: 172.20.0.1, server:
polygon.application.local, request: "GET /v1/credits HTTP/1.1",
upstream: "http://172.20.0.5:8080/v1/credits", host:
"polygon.application.local"
I have tried different solutions from Google to fix this problem, but have not fixed it yet.
There are my configs:
docker-compose.yaml
version: "3.9"
services:
nginx:
image: nginx:alpine
volumes:
- ${PROJECT_DIR}/deployments/nginx.conf:/etc/nginx/conf.d/default.conf:delegated
- ${PROJECT_DIR}/configs/ssl:/etc/nginx/ssl/:delegated
ports:
- "80:80"
- "443:443"
swagger_ui:
image: swaggerapi/swagger-ui
environment:
SWAGGER_JSON: /spec/api.swagger.yaml
volumes:
- ${PROJECT_DIR}/api/openapi-spec/api.swagger.yaml:/spec/api.swagger.yaml
credit_server:
build:
context: ..
dockerfile: ${PROJECT_DIR}/deployments/Dockerfile
args:
BUILD_APP_NAME: credit-server
depends_on:
credit_service_db:
condition: service_healthy
credit_service_db:
image: mysql:8.0
container_name: credit_service_db
restart: always
environment:
MYSQL_DATABASE: credit_service
MYSQL_USER: credit_service
MYSQL_PASSWORD: credit_service
MYSQL_ROOT_PASSWORD: credit_service
ports:
- '3306:3306'
expose:
- '3306'
healthcheck:
test: [ 'CMD-SHELL', 'mysqladmin ping -h localhost' ]
interval: 5s
timeout: 20s
retries: 10
nginx.conf
map $microservice $upstream {
credits credit_server:8080;
swagger swagger_ui:8080;
}
server {
listen 443 http2 ssl;
server_name polygon.application.local;
server_tokens off;
client_max_body_size 16m;
root /dev/null;
resolver 127.0.0.11 valid=30s;
ssl_certificate /etc/nginx/ssl/crt.pem;
ssl_certificate_key /etc/nginx/ssl/private.key.pem;
location / {
set $microservice "swagger";
proxy_pass http://$upstream;
}
location ~ ^/v1/(?<microservice>[\w\-]+) {
proxy_http_version 1.1;
proxy_set_header Host $http_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 http;
proxy_set_header X-Frame-Options SAMEORIGIN;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS,PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Headers,Access-Control-Allow-Origin,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
add_header 'X-Microservice' '$microservice';
add_header 'X-Proxy-Pass' '$upstream';
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS,PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Headers,Access-Control-Allow-Origin,Authorization';
proxy_pass http://$upstream;
}
}
Dockerfile for the credit_server
FROM alpine:latest
ARG BUILD_APP_NAME
ENV PROJECT_DIR=/go
RUN apk add tzdata
COPY ./build/${BUILD_APP_NAME} ${PROJECT_DIR}/bin/app
COPY ./configs ${PROJECT_DIR}/configs
COPY ./internal/migrations ${PROJECT_DIR}/migrations
CMD ${PROJECT_DIR}/bin/app -c ${PROJECT_DIR}/configs/config.yml -m container -p ${PROJECT_DIR}/migrations/
All containers start and work without errors.
I also send my requests from swagger and postman
The error you are getting is coming from NGINX, looks like it is finding the correct container to talk to, but nothing is listening on port 8080 in that container. It could be because you have misconfigured the listening port or could be because the application takes some time to start up, so it is not accepting connections at the time NGINX is trying to connect.
Try putting depends_on declarations into nginx section
depends_on:
credit_server:
condition: service_healthy
swagger:
condition: service_healthy
By default, my rest-host for the golang application was 127.0.0.1 or just localhost. But in nginx we specify listen 80, it means 0.0.0.0:80, and when I rewrote my host to 0.0.0.0, it will work!

Prestashop behind Nginx reverse proxy: redirect loop

I'm facing the following problem. I'm running VPS with docker containers (VPS provider doesn't provide NAT module, thus all containers that connecting to the Internet must work in host network_mode).
Natively, there is NGINX reverse proxy in order to distribute HTTP flow across the application containers. Now, I would like to run docker image with Prestashop and setup NGINX to route flow by domain there.
NGINX is configured to accept SSL connections and pass request to the container as follows
server {
listen 80;
listen [::]:80;
server_name test.my-domain.pl;
return 301 https://test.my-domain.pl$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name test.my-domain.pl;
ssl on;
ssl_certificate_key /etc/letsencrypt/live/my-domain.pl/privkey.pem;
ssl_certificate /etc/letsencrypt/live/my-domain.pl/fullchain.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy upgrade-insecure-requests;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy "strict-origin" always;
add_header X-XSS-Protection "1; mode=block";
location / {
proxy_http_version 1.1;
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 https;
proxy_set_header X-Scheme https;
proxy_pass_request_headers on;
proxy_pass "http://127.0.0.1:8402";
}
}
My docker-compose file looks like this:
version: '2'
services:
my-presta:
image: my-presta:1.7
network_mode: host
environment:
- PS_DOMAIN=test.my-domain.pl
- PS_HANDLE_DYNAMIC_DOMAIN=1
- PS_INSTALL_AUTO=0
my-mysql:
image: mysql:8.0.27
environment:
MYSQL_DATABASE: ***
MYSQL_USER: ***
MYSQL_PASSWORD: ***
MYSQL_ROOT_PASSWORD: ***
volumes:
- my-mysql:/var/lib/mysql
ports:
- '8403:3306'
command: --default-authentication-plugin=mysql_native_password
volumes:
my-mysql:
Here, I'm using my enhanced:) presta shop docker image my-presta which I build this way:
FROM prestashop/prestashop:1.7
COPY 000-default.conf /etc/apache2/sites-enabled/000-default.conf
COPY ports.conf /etc/apache2/ports.conf
COPY Link.php /var/www/html/classes/Link.php
000-default.conf and ports.conf files have changed VirtulHost port from 80 to 8402 to make apache server to work along with natively installed NGINX (port 80 and 443). 000-default.conf:
<VirtualHost *:8402>
...
</VirtualHost>
and ports.conf:
Listen 8402
Links.php file contains hack in method getBaseLink() where I force to return https. Relevat part of it:
public function getBaseLink($idShop = null, $ssl = null, $relativeProtocol = false)
{
...
$base = 'https://' . $shop->domain
...
}
Now, When I run the stack, install PrestaShop, connect it successfuly to the database I'm facing the infinitly redirect loop problem on '/' base path. Everything works fine on different paths, like /contact, /item-1 etc.
To be more specific the following curl gives me 302 return code and Location header pointing to https://test.my-domain.pl
curl http://127.0.0.1:8402/ -v -H 'Host: test.my-domain.pl' -H 'X-Schema: https' -H 'X-Forwarded-Proto: https'
Where the same curl but with extented path returns 200/404 and the HTML content
curl http://127.0.0.1:8402/contact -v -H 'Host: test.my-domain.pl' -H 'X-Schema: https' -H 'X-Forwarded-Proto: https'
In web browser is occurs to fail on https://test.my-domain.pl but it works on https://test.my-domain.pl/contact.
Any idea how to make it work?

jwilder/nginx-proxy: no access to virtual host

I have a NAS behind a router. On this NAS I want to run for testing Nextcloud and Seafile together. Everything should be set up with docker. The jwilder/nginx-proxy container does no work as expected and I cannot find helpful information. I feel I am missing something very basic.
What is working:
I have a noip.com DynDNS that points to my routers ip: blabla.ddns.net
The router forwards ports 22, 80 and 443 to my NAS at 192.168.1.11
A plain nginx server running on the NAS can be accessed via blabla.ddns.net, its docker-compose.yml is this:
version: '2'
services:
nginxnextcloud:
container_name: nginxnextcloud
image: nginx
restart: always
ports:
- "80:80"
networks:
- web
networks:
web:
external: true
What is not working:
The same nginxserver like above behind the nginx-proxy. I cannot access this server. Calling blabla.ddns.net gives a 503 error, calling nextcloud.blabla.ddns.net gives "page not found". Viewing the logs of the nginx-proxy via docker logs -f nginxproxy logs every test with blabla.ddns.net and shows its 503 answer, but when I try to access nextcloud.blabla.ddns.net not even a log entry occurs.
This is the docker-compose.yml for one nginx behind a nginx-proxy:
version: '2'
services:
nginxnextcloud:
container_name: nginxnextcloud
image: nginx
restart: always
expose:
- 80
networks:
- web
environment:
- VIRTUAL_HOST=nextcloud.blabla.ddns.net
nginx-proxy:
image: jwilder/nginx-proxy
container_name: nginxproxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock
networks:
- web
networks:
web:
external: true
The generated configuration file for nginx-proxy /etc/nginx/conf.d/default.conf contains entries for my test server:
# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
default $http_x_forwarded_proto;
'' $scheme;
}
# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
default $http_x_forwarded_port;
'' $server_port;
}
# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
# Connection header that may have been passed to this server
map $http_upgrade $proxy_connection {
default upgrade;
'' close;
}
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Default dhparam
ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
default off;
https on;
}
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log off;
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 off;
resolver 127.0.0.11;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";
server {
server_name _; # This is just an invalid value which will never trigger on a real hostname.
listen 80;
access_log /var/log/nginx/access.log vhost;
return 503;
}
# nextcloud.blabla.ddns.net
upstream nextcloud.blabla.ddns.net {
## Can be connected with "web" network
# nginxnextcloud
server 172.22.0.2:80;
}
server {
server_name nextcloud.blabla.ddns.net;
listen 80 ;
access_log /var/log/nginx/access.log vhost;
location / {
proxy_pass http://nextcloud.blabla.ddns.net;
}
}
Why is this minimal example not working?

nginx docker compose redirect delay

I'm having a particularly odd behaviour with my docker-compose and nginx setup. I am trying to have nginx proxy_pass requests to a backend web service. The web service is Spring Boot, but I don't believe that's relevant. My web service will issue a 302 redirect to users who are not authenticated, sending them to a /login page. This all seems to work as expected except for an indeterminate period of time when I bring the docker-compose up. Early requests to the service which result in 302 responses result in timeouts, whilst requests direct to the /login page return as expected immediately. After an indeterminate period of time, usually minutes, something seems to stabilise and everything works as expected. I've verified the behaviour using chrome from a client machine and curl directly on the host running the compose. I believe the 302 responses are somehow getting dropped but I'm not sure.
Can anyone spot a problem?
version: '3.5'
services:
proxy:
image: nginx:latest
container_name: "proxy"
restart: always
volumes:
- blah:/etc/nginx
ports:
- 80:80
- 443:443
webservice:
image: "webservice:latest"
container_name: "webservice"
restart: always
ports:
- 8080:8080
Nginx Config:
worker_processes auto;
events { }
http {
server {
listen 80 default_server;
listen 443 default_server ssl;
ssl_certificate /etc/nginx/cert;
ssl_certificate_key /etc/nginx/key;
if ($scheme = http) {
return 301 https://$host:443$request_uri;
}
gzip on;
gzip_types text/plain application/xml application/json application/javascript;
location / {
proxy_http_version 1.1;
proxy_pass http://webservice:8080/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host:$server_port;
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_set_header X-Forwarded-Port $server_port;
access_log /etc/nginx/log/access.log combined;
error_log /etc/nginx/log/error.log warn;
}
}
}

How to setup nginx as reverse proxy with LetsEncrypt SSL encryption using Docker

I am trying to setup SSL for my homepage (www.myhomepage.com) using LetsEncrypt on a nginx reverse-proxy. I have an additional host without SSL running for testing proxying to multiple hosts (www.myotherhomepagewithoutssl.com).
The reverse-proxy and two hosts are running in three separate docker containers.
I got both hosts to work without SSL, but the encrypted one does not work, when trying to use SSL. The LetsEncrypt certificates appear to be setup/obtained correctly and are persisted in a docker volume.
I am trying to follow and adapt this tutorial to setup the LetsEncrypt SSL encryption:
http://tom.busby.ninja/letsecnrypt-nginx-reverse-proxy-no-downtime/
When trying to connect to the SSL encrypted host under www.myhomepage.com using Firefox I get this error:
Unable to connect
The other non-encrypted host under www.myotherhomepagewithoutssl.com works. And as I stated above, when I have www.myhomepage.com setup without SSL (in the same way as www.myotherhomepagewithoutssl.com), it is also reachable.
My complete setup is listed below and consists of:
* reverse_proxy_testing.sh: Bash script to clean-up, build and start the containers.
* compose_reverse_proxy.yaml: Docker-Compose file.
* reverse_proxy.docker: Dockerfile for setting up the reverse-proxy with nginx.
* nginx.conf: nginx config-file for the reverse-proxy.
I suspect that my error is located somewhere inside nginx.conf, but I cannot find it.
Any help is much appreciated!
nginx.conf:
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
server {
deny all;
}
upstream myhomepage {
server myhomepage_blog:80;
}
upstream docker-apache {
server apache:80;
}
server {
listen 80;
listen [::]:80;
server_name www.myhomepage.com myhomepage.com;
return 302 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443;
server_name www.myhomepage.com myhomepage.com;
ssl_certificate /etc/letsencrypt/live/myhomepage.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myhomepage.com/privkey.pem;
location /.well-known {
root /var/www/ssl-proof/myhomepage.com/;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://myhomepage;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 900s;
}
}
server {
listen 80;
server_name www.myotherhomepagewithoutssl.com myotherhomepagewithoutssl.com;
location / {
proxy_pass http://docker-apache;
proxy_redirect off;
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;
}
}
}
reverse_proxy.docker:
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /var/www/ssl-proof/myhomepage.com/.well-known
RUN apk update && apk add certbot
compose_reverse_proxy.yaml:
version: '3.3'
services:
reverseproxy:
image: reverseproxy
ports:
- 80:80
restart: always
volumes:
- proxy_letsencrypt_ssl_proof:/var/www/ssl-proof
- proxy_letsencrypte_certificates:/etc/letsencrypt
apache:
depends_on:
- reverseproxy
image: httpd:alpine
restart: always
myhomepage_blog:
image: wordpress
links:
- myhomepage_db:mysql
environment:
- WORDPRESS_DB_PASSWORD=somepassword
- VIRTUAL_HOST=myhomepage.com
volumes:
- myhomepage_code:/code
- myhomepage_html:/var/www/html
restart: always
myhomepage_db:
image: mariadb
environment:
- MYSQL_ROOT_PASSWORD=somepassword
- MYSQL_DATABASE=wordpress
volumes:
- myhomepage_dbdata:/var/lib/mysql
restart: always
volumes:
myhomepage_dbdata:
myhomepage_code:
myhomepage_html:
proxy_letsencrypt_ssl_proof:
proxy_letsencrypte_certificates:
reverse_proxy_testing.sh:
#!/bin/bash
docker rm testreverseproxy_apache_1 testreverseproxy_myhomepage_blog_1 testreverseproxy_myhomepage_db_1 testreverseproxy_reverseproxy_1
docker build -t reverseproxy -f reverse_proxy.docker .
docker-compose -f reverse_proxy_compose.yml up

Resources