weserv / images

Source code of wsrv.nl (formerly images.weserv.nl), to be used on your own server(s).
https://wsrv.nl/
BSD 3-Clause "New" or "Revised" License
1.86k stars 187 forks source link

404 issue with local hosted service and docker-compose file #300

Closed uwekoenig closed 2 years ago

uwekoenig commented 2 years ago

We host all our services for development and test purposes on our internal servers with Docker Compose.

I have the issue that we get after approx. 30 seconds the JSON result error ... 404 ... The hostname of the origin is unresolvable (DNS) or blocked by policy. if we try to load an image with http://weservimages.our-local-domain.com:8082/?url=images.weserv.nl/lichtenstein.jpg&w=300&tint=red I tried pictures from our own servers with the same result, too.

Calling only http://weservimages.our-local-domain.com:8082 works and shows the start page immediately. So I think that the service is running.

Here my docker-compose.yml:

version: '3'

services:
  weservimages:
    image: ghcr.io/weserv/images:5.x
    container_name: weservimages
    environment:
      - shm-size=1gb
    ports:
      - 8082:80
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro

networks:
  proxy:
    external: true
kleisauke commented 2 years ago

Sounds like the IPv6 interface is not properly configured, see #206 for more information. If using Docker, you can try to switch to host networking by passing --network host to the command line (or you can use network_mode: "host", when using Docker compose).

Is the environment entry shm-size=1gb correct?

shm-size is not an environment variable, I think the correct usage in Docker compose would be:

@@ -4,8 +4,7 @@ services:
   weservimages:
     image: ghcr.io/weserv/images:5.x
     container_name: weservimages
-    environment:
-      - shm-size=1gb
+    shm_size: '1gb'
     ports:
       - 8082:80
     restart: unless-stopped
uwekoenig commented 2 years ago

@kleisauke Thank you for your feedback.

I changed the docker-compose.yml to the following now:

version: '3'

services:
  weservimages:
    image: ghcr.io/weserv/images:5.x
    container_name: weservimages
#    shm-size: "1gb"
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    network_mode: "host"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro

Unfortunately the result is exactly the same like before. The server itself does not have a IPv6 configuration.

I tried also with a Traefik reverse proxy. Same result again. After 30 seconds I get the 404 again.

version: '3'

services:
  weservimages:
    image: ghcr.io/weserv/images:5.x
    container_name: weservimages
#    shm-size: "1gb"
    ports:
      - 8082:80
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.weservimages.entrypoints=http"
      - "traefik.http.routers.weservimages.rule=Host(`weservimages.our-local-domain.com`)"
      - "traefik.http.routers.weservimages-secure.entrypoints=https"
      - "traefik.http.routers.weservimages-secure.rule=Host(`weservimages.our-local-domain.com`)"
      - "traefik.http.routers.weservimages-secure.tls=true"
      - "traefik.http.routers.weservimages-secure.service=weservimages"
      - "traefik.http.services.weservimages.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

The container seems to get no IPv6 configuration. When I access the container and run ip a I see only IPv4 settings.

root@docker12021:/opt/containers/weservimages# docker-compose exec weservimages bash
[root@3cc1ae0d0ea2 imagesweserv]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:08 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.8/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever

Any other ideas? Does the container not work without IPv6? Do I need to give the server a white list of allowed image source URLs to work?

RobinGiel commented 2 years ago

It looks like this issue is also the same as mine, I'm also trying to use a reverse proxy in order to use https instead of http. but no luck. here is my issue #301

kleisauke commented 2 years ago

See https://github.com/weserv/images/issues/206#issuecomment-567015037 if looking up IPv6 addresses is not desired. Note that the pre-built Docker image requires changing /etc/nginx/imagesweserv.conf instead (since the nginx configuration was 'deployed' during the image build).

@RobinGiel This issue is about connecting to upstream servers, so I don't think it's similar to your issue.

uwekoenig commented 2 years ago

@kleisauke Thank you for your feedback which helped me a lot to solve the issues!

Especially the logs in /var/log/nginx/weserv-local-error.log (comments in #206) were informative. It was a combination of a few problems. Here my config files.

docker-compose.yml

version: '3'

services:
  weservimages:
    image: ghcr.io/weserv/images:5.x
    container_name: weservimages
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - ./data/imagesweserv.conf:/etc/nginx/imagesweserv.conf
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.weservimages.entrypoints=http"
      - "traefik.http.routers.weservimages.rule=Host(`weservimages.our-local-domain.com`)"
      - "traefik.http.routers.weservimages-secure.entrypoints=https"
      - "traefik.http.routers.weservimages-secure.rule=Host(`weservimages.our-local-domain.com`)"
      - "traefik.http.routers.weservimages-secure.tls=true"
      - "traefik.http.routers.weservimages-secure.service=weservimages"
      - "traefik.http.services.weservimages.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

data/imagesweserv.conf (Modifications are marked with #Modification Start and #Modification End):

# Please adjust cache size (max_size=250m) to a value that you can accommodate in RAM! Advised values: 2 GB RAM: 500m, 4 GB RAM: 1g, 8 GB RAM: 2g, etc..

proxy_cache_path /dev/shm/proxy_cache inactive=8h levels=1:2 keys_zone=images:512m max_size=250m loader_files=5000 use_temp_path=off;
proxy_cache_min_uses 2;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_buffers 256 8k;
proxy_buffering on;

upstream images {
    server 127.0.0.1:80;

    # a pool with at most 200 connections
    keepalive 200;
}

#upstream redis {
#    server 127.0.0.1:6379;
#
#    # Or: server unix:/var/run/redis/redis.sock;
#
#    # a pool with at most 1024 connections
#    keepalive 1024;
#}

#geo $limit {
#    default 1;
#    10.0.0.0/8 0;
#    192.168.0.0/24 0;
#}

#map $limit $limit_key {
#    0 "";
#    1 $remote_addr;
#}

server {
    listen 80;
#Modification Start
    server_name weservimages.our-local-domain.com;
#Modification End
    access_log off;
    error_log /var/log/nginx/weserv-local-error.log;

    root /var/www/imagesweserv/public;
    index index.html;

    error_page 404 /404.html;

    allow 127.0.0.1;
#Modification Start
#Add Docker IPs
    allow 172.18.0.0/24;
#Modification End
    allow ::1;
    deny all;

    location / {
#Modification Start
#       resolver 8.8.8.8; # Use Google's open DNS server
        resolver 127.0.0.11 ipv6=off; # Use the DNS server from /etc/resolv.conf of the container
#Modification End
        weserv proxy;
    }

    location /static {
        weserv filter;

        alias /var/www/imagesweserv/public;
    }
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name _;

    access_log /var/log/nginx/weserv-access.log main buffer=4096 flush=5m;
    access_log /var/log/nginx/weserv-stats.log stats buffer=4096 flush=5m;
    error_log /var/log/nginx/weserv-error.log;

    root /var/www/imagesweserv/public;
    index index.html;

    add_header Last-Modified "" always; # Always remove the Last-Modified header
    add_header Access-Control-Allow-Origin "*" always;
    add_header X-Images-Api "5" always;

    location / {
        expires 1y; # Far-future expiration for static files
        try_files $uri $uri/index.html$is_args @proxy;
    }

#    location ~ ^/quota/?$ {
#        rate_limit $limit_key requests=2500 period=10m burst=2499;
#        rate_limit_quantity 0;
#        rate_limit_pass redis;
#        rate_limit_headers on;
#
#        error_page 404 =200 @quota;
#    }

#    location @quota {
#        default_type application/json;
#        add_header Cache-Control "no-store, must-revalidate";
#        if ($limit = 0) {
#          return 200 '{"status":"success", "code":200, "message":"Your IP address ($remote_addr) bypasses the rate limiter, have fun!"}';
#        }
#        return 200 '{"X-RateLimit-Limit":$sent_http_x_ratelimit_limit, "X-RateLimit-Remaining":$sent_http_x_ratelimit_remaining, "X-RateLimit-Reset":$sent_http_x_ratelimit_reset}';
#    }

    location @proxy {
        proxy_cache images;
#Modification Start
        proxy_cache_key "$request_method|weservimages.our-local-domain.com|$request_uri";
#Modification End
        proxy_cache_methods GET HEAD;
        proxy_cache_bypass $http_pragma $http_authorization;
        proxy_cache_valid 200 301 410 7d;
        proxy_cache_valid 429 500 0;
        proxy_cache_valid any 15m;
        proxy_cache_use_stale error timeout updating;

        proxy_pass http://images;
#Modification Start
        proxy_set_header Host weservimages.our-local-domain.com;
#Modification End
        proxy_set_header X-Original-Host $http_host;
        proxy_set_header X-Original-Scheme $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;

        # Enable the upstream persistent connection
        proxy_http_version 1.1;
        proxy_set_header Connection "";

        # 2500 allowed requests in 10 minutes
#        rate_limit $limit_key requests=2500 period=10m burst=2499;
#        rate_limit_pass redis;
    }
}
kleisauke commented 2 years ago

Great, I'll close. Note that in the above example, you probably don't want weservimages.our-local-domain.com to be reachable from the outside, as that would bypass the proxy cache.