2

I'm creating an application with docker-compose, vue.js, and phoenix/elixir. So far the phoenix application will work on localhost, but will not work when I run the application using docker-compose + NGINX and it's been difficult to debug. Any advice or suggestions would be helpful. The phoenix application itself does not have any of the configuration options changed from the "hello world" application and only adds in socket functionality for a chat room.

Here is the docker-compose file:

version: "3.9"

networks: 
  main_network:

volumes:
  volume1:
  varwwwcertbot:
  certbotconf:
  data_volume:

services:
  phx: 
    build:
      context: ./phx
    restart: always
    volumes:
      - ./phx:/phx
    ports: 
      - "4000:4000"
    depends_on:
      db:
        condition: service_healthy
    networks:
      - main_network
  db:
    image: postgres
    restart: always
    volumes:
      - ./docker-entrypoint-initdb.d/init.sql:/docker-entrypoint-initdb.d/init.sql
      - data_volume:/var/lib/postgresql/data
    environment:
      - POSTGRES_NAME=dev-postgres
      - POSTGRES_USER=pixel
      - POSTGRES_DATABASE=lightchan
      - POSTGRES_PASSWORD=exploration 
    ports: 
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U pixel"]
      interval: 5s
      timeout: 5s
      retries: 20
    networks:
      - main_network
  frontend:
    build: 
      context: ./frontend
    restart: always
    volumes:
      - './frontend:/app'
      - '/app/node_modules'
    ports: 
      - "3000:3000"
    networks:
      - main_network
    depends_on:
      - "phx"
  nginx:
    build:
      context: ./nginx
    restart: always
    ports:
      - "80:80"
      - "443:443" 
    volumes:
      - volume1:/usr/share/nginx/html
      - varwwwcertbot:/var/www/certbot
      - certbotconf:/etc/letsencrypt 
    networks:
      - main_network
  certbot:
    image: certbot/certbot:latest
    volumes: 
      - varwwwcertbot:/var/www/certbot
      - certbotconf:/etc/letsencrypt
    networks:
      - main_network

Here is the nginx file:

events{

}

http{

     map $http_upgrade $connection_upgrade {
         default Upgrade;
         ''      close;
     }

     upstream websocket {
         server 164.92.157.124:4000;
     }

     server {
         listen 80;
         server_name localhost lightchan.org www.lightchan.org;
         root /usr/share/nginx/html;

         location /.well-known/acme-challenge/ {
            root /var/www/certbot;
         }

         if ($scheme = http) {
           return 301 https://lightchan.org$request_uri;
         }
     }

    server {
         listen 443 default_server ssl http2;
         listen [::]:443 ssl http2;
         server_name localhost lightchan.org www.lightchan.org;
         ssl_certificate /etc/letsencrypt/live/lightchan.org/fullchain.pem;
         ssl_certificate_key /etc/letsencrypt/live/lightchan.org/privkey.pem;

            location /media/pics/ {
                 autoindex on;
            }
            location / {
                 proxy_pass http://frontend:3000;
                 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        Host $http_host;
                 proxy_intercept_errors  on;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection "upgrade";
            }
            location ^~ /socket/ {
                 proxy_pass http://websocket;
                 add_header X-uri "$uri";
                 proxy_http_version 1.1;
                 proxy_set_header        X-Forwarded-Proto $scheme;
                 proxy_set_header        Host $host;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection $connection_upgrade;
                # proxy_set_header Upgrade $http_upgrade;
                # proxy_set_header Connection "upgrade";
            }
            location ^~ /api/ {
                 proxy_pass http://phx:4000;
                 add_header X-uri "$uri";
                 proxy_http_version 1.1;
                 proxy_set_header        X-Forwarded-Proto $scheme;
                 proxy_set_header        Host $host;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection $connection_upgrade;
                # proxy_set_header Upgrade $http_upgrade;
                # proxy_set_header Connection "upgrade";
            }
    }
}

Note here that I attempted to proxy through an upstream for a /socket/ config and also attempted to use /api/ just using the phx docker tag. Both frontend and phx are linked in the docker-compose file, so they should be coming through. I've also turned on the 'upgrade' feature of Connection so this should be forwarding websockets too.

The phoenix application itself, still has the / front page uri, so I would suspect that being able to navigate to either www.lightchan.org/api or www.lightchan.org/socket would then allow me to see the phoenix hello world splash page, but instead there's a 502 error.

Any suggestions?

EDIT:

I've edited config/config.exs in the phoenix application to run on host 127.0.0.1 like this:

# Configures the endpoint
config :my_app, MyAppWeb.Endpoint,
  url: [host: "127.0.0.1"],
  render_errors: [view: MyAppWeb.ErrorView, accepts: ~w(html json), layout: false],
  pubsub_server: MyApp.PubSub,
  live_view: [signing_salt: "blah"]

and tested this running on locally, and it works, correctly showing the splash page at /. I've attempted to get this to work using http://<SERVER IP>:4000 on my server, but no luck.

EDIT EDIT:

Frustratingly, my autoindex for /media/pics is not working, but rather routing to the the frontend. Here is an embarrassingly thorough guide on routing priorities in NGINX (Guide on how to use regex in Nginx location block section?) and here (Nginx location priority). According to the second link:

location ^~ /images/ {
  # matches any query beginning with /images/ and halts searching,
  # so regular expressions will not be checked.
  [ configuration D ] 
}

should mean that

        location ^~ /media/pics/ {
             autoindex on;
        }
        location / {
             <...>

should stop searching and the return an autoindex. So https://www.lightchan.org/media/pics/myimage.png should return myimage.png. That doesn't work and neither does

        location /media/pics/ {
             autoindex on;
        }

Although I could have sworn it was working before...hmm.

yosemeti
  • 206
  • 4
  • 15
  • Part of the answer was supplied by a helpful user on discord who linked to here: https://stackoverflow.com/questions/10631933/nginx-static-file-serving-confusion-with-root-alias/10647080#10647080. The /media/pics block should look like the following: location ^~ /media/pics/ { alias /media/pics/; autoindex on; } – yosemeti Mar 23 '22 at 00:55

1 Answers1

2

Thanks to GreenMachine on Discord the answer was found here:

https://dev.to/eikooc/using-docker-for-your-elixir-phoenix-application-n8n

change dev.exs in config:

# from this:
http: [ip: {127, 0, 0, 1}, port: 4000],
# to this:
http: [ip: {0, 0, 0, 0}, port: 4000],
yosemeti
  • 206
  • 4
  • 15