I'm attempting to get a next.js app running in a docker container based on phusion/passenger-docker.
I have what I think is a complete setup based on passenger-docker documentation but I'm getting a 404 page from nginx.
A docker log dump shows that passenger or nginx, is looking for index.html
[error] 48#48: *1 "/home/app/nhe_app/index.html" is not found
My startup file is /home/app/nhe_app/server.js
Dockerfile final stage:
# Build production container from builder stage
FROM phusion/passenger-nodejs:1.0.8
# Set correct environment variables.
ENV HOME /root
ENV NODE_ENV=production
# Use baseimage-docker's init system.
CMD ["/sbin/my_init"]
# Enable Nginx and Passenger
RUN rm -f /etc/service/nginx/down
WORKDIR /home/app/nhe_app
RUN rm /etc/nginx/sites-enabled/default
COPY --chown=app:app ./nhe_app.conf /etc/nginx/sites-enabled/nhe_app.conf
COPY --chown=app:app ./secret_key.conf /etc/nginx/main.d/secret_key.conf
COPY --chown=app:app ./gzip_max.conf /etc/nginx/conf.d/gzip_max.conf
COPY --chown=app:app --from=builder /app/server.js /app/.env /home/app/nhe_app/
COPY --chown=app:app --from=builder app/src /home/app/nhe_app/src
COPY --chown=app:app --from=builder app/node_modules /home/app/nhe_app/node_modules
# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
nginx configuration - nhe_app.conf:
server {
listen 80;
server_name glen-mac.local;
root /home/app/nhe_app/server.js;
passenger_enabled on;
passenger_user app;
passenger_startup_file server.js;
}
I expect that passenger will start nginx and run my app.
When I build and start the docker container it seems to expect index.html.
I'm building the docker container with
docker image build -t nhe_app .
And running it with
docker container run --name nhe_app -p 80:3000 nhe_app
Browsing to http://glen-mac.local/ shows nginx's formatted 404 page.
How can I configure passenger-docker to look for and execute my server.js rather than index.html?
There are several subtle problems in the OP question.
Most notably, Passenger seems to require that the app root path, defined by root in the nginx configuration above, has a top level folder named public. This folder must not contain an index.html file and probably should be empty. This is shown in examples, but not spelled out as a hard requirement in the docs.
Second major error is that Passenger bypasses the port specified in the app's server.js (3000 in this case) and replaces it with the port specified in the nginx configuration. So the docker run command changed from:
docker container run --name nhe_app -p 80:3000 nhe_app
to
docker container run --name nhe_app -p 80:80 nhe_app.
Otherwise, the best advice I can give is:
Learn the Passenger basics through a local installation (without Docker). Get the Passenger demo app working.
Get your app working in that local Passenger installation.
Apply what you have learned to implementing your app in passenger-docker.
server {
listen 7063;
server_name localhost;
root /home/app/nhe_app;
passenger_enabled on;
passenger_min_instances 1;
passenger_max_request_queue_size 100; # default: 100
passenger_app_env staging; # NODE_ENV; default: staging
passenger_app_root /home/app/nhe_app;
passenger_app_type node;
passenger_startup_file server.js;
}
Related
I'm trying to create a reverse proxy using nginx running in docker. I have set up the nginx.conf file and it's running fine locally. However, I don't know how to set up the nginx docker with this changed nginx.conf file. Is there any way to do this?
Update: I have been able to change the nginx.conf file inside Docker. However, going to localhost:80/go returns a 502 Bad Gateway. I have a go app running on port 8081 using go run main.go and a python app running on port 8080 using flask run. I'm on a Manjaro VM.
This is the server part of the nginx.conf file
server {
listen 80;
location / {
return 200 'hey there, welcome to our amazing app :)';
}
location /cbl {
proxy_pass http://127.0.0.1:8080;
}
location /go {
proxy_pass http://127.0.0.1:8081;
}
}
And this is the Dockerfile
FROM nginx
RUN mv /etc/nginx/nginx.conf /etc/nginx/nginxorig.conf
#RUN pwd
#RUN cp /home/shark/hwr-nginx/nginx.conf /etc/nginx/conf.d/default.conf
VOLUME /usr/share/nginx/html
VOLUME /etc/nginx
How do I fix this?
[shark#shark-virtualbox hwr-nginx]$ sudo docker build . -t nginx
Sending build context to Docker daemon 7.168kB
Step 1/3 : FROM nginx
---> 7084cd82dcbb
Step 2/3 : RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_orig
---> Running in 80e011c5b125
mv: cannot stat '/etc/nginx/nginx.conf': No such file or directory
The command '/bin/sh -c mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_orig' returned a non-zero code: 1
[shark#shark-virtualbox hwr-nginx]$ cat Dockerfile
FROM nginx
RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_orig
RUN cp hwr-nginx/nginx.conf /etc/nginx/nginx.conf
```` RUN mv and RUN cp are also not working for me :(.
You need to copy your nginx.conf to your container:
For example: COPY conf /etc/nginx
Docs here: https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-docker/#managing-content-and-configuration-files
In your Dockerfile, add an instruction to copy your project's reverse proxy configured ngxin.conf into the docker image you intend to build, in the location where nginx will look for its configurations. For example, assuming your base image is Debian, you could do the following in your Dockerfile:
# Move the default conf out of the way
RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_orig
# Copy in your project's new nginx conf
RUN cp my_project/nginx.conf /etc/nginx/nginx.conf
I create the following docker image
# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
FROM tiangolo/node-frontend:10 as build-stage
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY ./ /app/
RUN CI=true npm test
RUN npm run build
# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx:1.15
COPY --from=build-stage /app/build/ /usr/share/nginx/html
# Copy the default nginx.conf provided by tiangolo/node-frontend
COPY ./nginx.conf /etc/nginx/conf.d/v2.myapp.io
Where the nginx.conf is
server {
listen 80;
server_name serverip v2.myapp.io www.v2.myapp.io;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
include /etc/nginx/extra-conf.d/*.conf;
}
And then i execute the following sh
docker build -t mycontainer .
docker push mycontainer:latest
ssh root#ip 'docker pull mycontainer:latest'
ssh root#ip 'docker stop mycontainer'
ssh root#ip 'docker rm mycontainer'
ssh root#ip 'sudo docker run -p 8080:80 -it -d --name mycontainer mycontainer'
Well it works fine, but the address v2.myapp.io points to a blank nginx page, so i guess i have some sort of missconfiguration. But im not sure what else can be happening
Can someone help with this issue?
I remember that when I used to do all this manually, I had a sites-enabled, and a sites-available folder, i have tried creating them and puting the nginx.conf file in but i had no luck
What is failing there?
I have a flask app running in AWS ec2 inside a docker container and I am having latency problems. I figured this is because inside the container, localhost routes to both ipv4's 127.0.0.1 and ipv6's ::1 (based on some other SO posts). I found this blog post which addresses the issue exactly. But in the blog he uses nginx, which I've never used before. He has an nginx config file:
location / { try_files $uri #project; }
location #project {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
}
and I'm not sure how I can place this in the container so that it reads properly. I read somewhere that it goes in /etc/nginx, but then how do I edit the dockerfile to include this conf there?
This is the Dockerfile he suggests. Is the line ADD nginx /etc/nginx where the file is getting copied in? and he just didn't give the file an extension?
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y build-essential nginx python3.4 python3.4-dev
RUN easy_install3 pip
WORKDIR /project
ADD requirements.txt /project/requirements.txt
RUN pip install -r requirements.txt
ADD . /project
ADD nginx /etc/nginx
CMD uwsgi -s /tmp/uwsgi.sock -w project:app --chown-socket=www-data:www-data --enable-threads & \
nginx -g 'daemon off;'
Yes, he is adding the file nginx to the container file system location /etc/nginx/
Personally I'd name the file nginx.conf as that is the default name according to the nginx documentation.
By default, the configuration file is named nginx.conf and placed in
the directory /usr/local/nginx/conf, /etc/nginx, or
/usr/local/etc/nginx.
Also, I'd recommend using COPY in stead of ADD according to the Best practices for writing Dockerfiles
For other items (files, directories) that do not require ADD’s tar
auto-extraction capability, you should always use COPY.
To make this work you'll need to install nginx on the container you're running flask on.
I just take a few modifications on a Dockerfile to run it with nginx on Heroku. Something special about Heroku is, that everything is running as non-root. Second certain behaviour is the use of a random Port which comes from Heroku itself and you can't be modified. They provide the env $PORT which you should bind to nginx. If Heroku recognizes that something isn't bind to that port it stops the entire container. Question is:
How can I bind nginx to a given env variable in order to have a dynamic port in the nginx-site.conf?
I tried to use things like follows in the Dockefile:
env PORT; in nginx.conf and listen PORT_from_env; in the nginx-site.conf
Also tried listen 80; in the nginx-site.conf and RUN /bin/sed -i "s/listen 80/listen ${PORT}/" /etc/nginx/sites-available/default.conf in the Dockerfile
I am absolutely above my capabilities. Someone has an idea or can help? It be very helpful!
Further information:
https://devcenter.heroku.com/articles/dynos#web-dynos
I got it working for my app by following this example :
Step 1: listen to $PORT in default.conf.template
server {
listen $PORT default_server;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Step 2: add this directive to your Dockerfile
COPY default.conf.template /etc/nginx/conf.d/default.conf.template
Step 3: add this at the end of your Dockerfile
CMD /bin/bash -c "envsubst '\$PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf" && nginx -g 'daemon off;'
I'll show a solution which doesn't require to write a new Dockerfile, you can use the offical nginx images.
Like #Jimmy's solution we'll use the envsubst command which substitutes environment variables in shell format strings.
This command is available with the offical nginx image and also with the alpine version.
Step #1
write your nginx configuration in a template file - let's call it: site.template:
server {
listen ${PORT};
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
Notice the PORT placeholder.
Step #2 - with docker compose
Mount that inside the /etc/nginx/conf.d directory and then execute the envsubst command to use the template as a reference for default.conf:
web:
image: nginx:alpine
volumes:
- ./site.template:/etc/nginx/conf.d/site.template
ports:
- "3000:8080"
environment:
- PORT=8080
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/site.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
Notice that:
1. You need to execute the nginx daemon after that.
2. I used /bin/sh and not /bin/bash because my base image is alpine.
Step #2 (Another option) - inline docker run
If, for some reason you don't want to work with docker-compose you can use the following bash script:
#!/usr/bin/env bash
##### Variables #####
PORT=8080 #Or $1 if you pass it from command line
TEMPLATE_DIR=$(pwd)/site.template
TEMPLATE_REMOTE_DIR=/etc/nginx/conf.d/site.template
IMAGE_NAME=nginx:alpine
echo "Starting nginx on port: $PORT ..."
##### The docker command #####
docker run -p 3000:$PORT -v $TEMPLATE_DIR:$TEMPLATE_REMOTE_DIR $IMAGE_NAME \
/bin/sh -c "envsubst < $TEMPLATE_REMOTE_DIR > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
You need to update your nginx configuration at boot time.
See this buildpack as an example (I haven't tested that it does work).
I'm working on the scenario where I need to have:
1. nginx running on the host machine
2. rails app running inside docker container
My initial work included adding Dockerfile into rails app directory on host which looks like this:
ubuntu#ubuntu-xenial:~/rails_docker$ cat Dockerfile
FROM ruby:2.1-onbuild
ENV HOME /home/rails/webapp
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
WORKDIR $HOME
# Install gems
ADD Gemfile* $HOME/
RUN bundle install
# Add the app code
ADD . $HOME
EXPOSE 8080
EXPOSE 5432
Since I already have nginx on host, it is configured to look at directory where rails application exists on host machine:
ubuntu#ubuntu-xenial:~$ cat /etc/nginx/sites-available/www.testblog.io.conf
# MANAGED BY PUPPET
server {
listen *:8080;
server_name www.testblog.io;
index index.html index.htm index.php;
access_log /var/log/nginx/www.testblog.io.access.log combined;
error_log /var/log/nginx/www.testblog.io.error.log;
location / {
root /home/ubuntu/rails_docker/public;
index index.html index.htm index.php;
}
passenger_enabled on;
passenger_ruby /usr/local/rvm/wrappers/default/ruby;
}
I'm able to build docker image and my next idea is following:
1. Declare /home/ubuntu/rails_docker as a host volume when running "rails container"
2. Expose ports 8080:8080 and 5432:5432
Command I use is following:
ubuntu#ubuntu-xenial:~/rails_docker$ docker run -d -p 8080:8080 --name examplerails -v /home/ubuntu/rails_docker:/home/rails/webapp railsapptest
82c8aa45b8c1a405e198a565feabf105d1afcbb1c37f8b7b11bf764395ed8c4e
When I check logs:
ubuntu#ubuntu-xenial:~/rails_docker$ docker logs -f examplerails
Switch to inspect mode.
For some reason, it goes into irb mode. Any idea what I'm doing wrong?
Thanks in advance,
Bakir
You need to have a CMD instruction in your Dockerfile. That is the command that is run when you start up your Docker container. If you don't specify a command, it will run whatever your FROM image uses, which you can see is 'irb' if you look at the Ruby docker image.
You can read more about the CMD instruction and everything else about Dockerfiles in the Docker documentation.