I've recently setup an Unraid server in my house and wanted to use the opportunity to learn a bit about Docker by developing a simple web app and deploy it to the server.
I'm writing this series to leave a paper trail for other people to follow since I ran into a number of issues.
I am by no means a docker expert. This is all from the point of view of a docker novice.
First a few basic details about my setup:
- It's March 2021
- Development PC is a Windows 10 version: 10.0.19042.867
- Unraid is version: 6.9.1
- Docker Engine is version: 20.10.5
- I've installed WSL2
Here are some links to get the basics up and running:
The web app I'm building has a frontend (Angular/Ionic) and a backend (NodeJS). I'm not really going to go into those things as this is mostly about just getting docker working on Unraid.
Creating the Docker images and containers for my App
Initially I was going to use PHP for the server - because it's what I already had - but I found this excellent:
NGINX with Docker and Node.js — a Beginner’s guide
The end product of this guide is an NGINX container that serves as a reverse proxy for a Node.js server.
I didn't know what a reverse proxy was, but essentially it lets you access another service through the endpoint of NGINX. You can configure NGINX to pass your requests to another server and ferry the response back. This can be helpful if you want to hide the actual location of the other server. NGINX can also take care of all the HTTPS security stuff for your reversed proxied server.
This guide doesn't add a frontend so I thought I'd try to do that myself and followed the documentation from NGINX: NGINX Docs | Serving Static Content
Setting up the NGINX docker container
It only requires 2 files to setup NGINX in a container
-
Dockerfile
the instructions to create the image. -
default.conf
the configuration of the server.
That's about as easy as anyone could hope for.
The Dockerfile
literally just splats the configuration onto the server and you're done.
FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf
Now my default.conf
looks like this:
server {
root /data;
location /media {
rewrite ^/media(.*)$ $1 break;
root /media;
}
location /nodeserver {
rewrite ^/nodeserver(.*)$ /$1 break;
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 $scheme;
proxy_pass http://nodeserver:5000;
}
}
This is somewhat similar to Ashwin's guide, but I'll try to explain what I'm doing here.
First up root /data;
is the root directory used to try to find the static content. I'm expecting the container to be able to find some HTML (particularly index.html
) in the /data
folder. I'll accomplish this later by mounting a folder on my system to the /data
folder in the container.
The location /media
block I use to serve some media files from another folder separate from the /data
folder. Whenever someone requests a url that starts with /media/
, then we serve from root /media;
instead of the default root.
I did this without the rewrite
line first, but then my requests would all be prefixed with /media
so when I request http://localhost/media/myfile.mp4
NGINX would try to serve the file /media/media/myfile.mp4
. To remove the first /media
I used this rewrite rule. A solution I found here: serverfault | how to remove location block from $uri in nginx configuration?
Finally, there is the /nodeserver
location, this is my access to the backend. Here I setup the reverse proxy as described in Ashwin's guide. I use the same rewrite rule here to remove the prefix from the requests forwarded to the backend. It's really crucial to note the / prefix in /$1
, this won't work with just $1
. I found the solution to that here
Node.JS container setup
I used the same approach as in Ashwin's guide.
Here is the Dockerfile
I used to create my node server:
FROM node:alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "index.js"]
docker-compose for local deployment
I found Docker quite cumbersome before I made it to the docker-compose
stage. It does make it a lot easier.
For a local deployment of this app, I need to spin up my two containers together and mount in a /data
and a /media
folder.
docker-compose.yml
for that looks something like this:
version: "3.8"
services:
nodeserver:
build:
# home-video-server has the nodeserver node.js DockerFile
context: ./home-video-server
nginx:
restart: always
build:
# home-server-nginx has the NGINX DockerFile
context: ./home-server-nginx
ports:
- "81:80"
volumes:
# Map the subfolder home-video/www to the /data folder
- ./home-video/www:/data
# and put my videos in the media folder
- c:\Users\jacob\videos:/media
You can use docker-compose up --build
to update the images and restart the containers.
In the default.conf for the NGINX server, you may have noticed that it refers to nodeserver by http://nodeserver:5000/
this kind of reference is only possible because we used docker compose with both containers. It's facilitated by a docker network that's created automatically. See Docker Compose Documentation on Networking.
Next time I'll explain how I managed to deploy the containers to my Unraid server using SSH.
Top comments (0)