TheYuwana

TheYuwana

Phoenix app in docker with ssl not receiving anything on port 443

Hey there fellow devs,

For the love of everything, I can’t seem to get this to work… I have a docker container with a phoenix app running in there. It’s hosted on a subdomain “sub.example.com” and I need to serve it with https.

So I got myself a wildcard SSL certificate, installed it, configured the production file and exposed 80 and 443 ports of the docker container.

Tried it out and port 80 works fine, but 443 is always returning a “ERR_CONNECTION_RESET”. The logs is showing nothing on 443, but 80 works fine.

Been trying for awhile now, and now i need your help. Any idea on whats wrong? Check the code below:

Dockerfile

FROM bitwalker/alpine-elixir-phoenix:latest

# create app folder
RUN mkdir /app
WORKDIR /app
COPY . .

# setting the port and the environment (prod = PRODUCTION!)
EXPOSE 80
EXPOSE 443

# install dependencies (production only)
RUN mix local.rebar --force
RUN mix deps.get --only prod
RUN mix compile

prod.exs

config :example, ExampleWeb.Endpoint,
  http: [port: 80],
  url: [host: "sub.example.com"],
  cache_static_manifest: "priv/static/cache_manifest.json",
  https: [
    cipher_suite: :strong,
    otp_app: :example,
    port: 443,
    keyfile: System.get_env("SSL_KEY_PATH"),
    certfile: System.get_env("SSL_CERT_PATH"),
    cacertfile: System.get_env("SSL_CHAINED_CERT_PATH")
  ]

curl https://sub.example.com/ --verbose result:

*   Trying 64.225.24.82...
* TCP_NODELAY set
* Connected to sub.example.com (64.225.24.82) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to sub.example.com:443
* Closing connection 0
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to sub.example.com:443

Marked As Solved

TheYuwana

TheYuwana

Alright, after days of searching, trial and error and discussions on this post. It finally works with the following configurations! Thanks to everyone and especially @egze with helping out and sparring!

Btw both nginx and phoenix are in the same docker conatiner.

Phoenix - prod.exs

config :example, ExampleWeb.Endpoint,
  http: [port: 5000],
  url: [host: "sub.example.com", port: 5000]

nginx config

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

server {
  server_name sub.example.com;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  ssl_certificate /etc/nginx/ssl/example_chained.pem;
  ssl_certificate_key /etc/nginx/ssl/example.pem;

  large_client_header_buffers 4 16k;

  location ~ live/websocket {
    proxy_http_version 1.1;
    proxy_set_header Origin '';
    proxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_ssl_server_name on;
    proxy_pass http://0.0.0.0:5000;
    break;
  }

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_ssl_server_name on;
    proxy_pass http://0.0.0.0:5000;
    break;
  }
}

Also Liked

egze

egze

Something else to think about is to let Nginx or other web server handle the SSL part, and proxy_pass requests to upstream. Then you can just run your Phoenix app on port 4000 and not worry about configuring ssl in Phoenix.

This is how I run my phoenix site with nginx in between.

upstream myapp {
  server localhost:4000;
}

server {
  server_name myapp.de;
  listen 443 ssl http2;
  listen [::]:443 ssl http2 ipv6only=on;

  ssl_certificate /etc/letsencrypt/live/myapp.de/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/myapp.de/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

  client_max_body_size 50m;

  location ~* \.(eot|ttf|woff)$ {
    add_header Access-Control-Allow-Origin *;
  }

  location ~* ^.+\.(css|js|ico|jpg|jpeg|png|svg|woff|woff2)$ {
    root /var/www/apps/myapp.de/current/lib/myapp-0.1.0/priv/static;
    etag off;
    expires max;
    add_header Access-Control-Allow-Origin *;
    add_header Cache-Control public;
  }

  location ~ live/websocket {
    proxy_http_version 1.1;
    proxy_set_header Origin '';
    proxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_pass http://myapp;
    break;
  }

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://myapp;
    break;
  }
}
stefanchrobot

stefanchrobot

How are you running the container? EXPOSE doesn’t do anything, really:

EXPOSE

EXPOSE <port> [<port>/<protocol>...]

The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified.

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

egze

egze

Because you can also use pure Erlang/Elixir to host your site if you want. SSL can certainly be done with pure Phoenix. Just that for me it’s not so practical. I host multiple sites on one box and I only have one 443 port :slight_smile:

Where Next?

Popular in Questions Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement