Nginx – SSD Nodes https://www.ssdnodes.com VPS Cloud Hosting For Hundreds Less Sun, 18 May 2025 19:54:23 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 https://www.ssdnodes.com/wp-content/uploads/2024/09/fav.svg Nginx – SSD Nodes https://www.ssdnodes.com 32 32 How To Use Nginx As A Reverse Proxy With SSL https://www.ssdnodes.com/blog/how-to-use-nginx-as-a-reverse-proxy-with-ssl-tutorial/ https://www.ssdnodes.com/blog/how-to-use-nginx-as-a-reverse-proxy-with-ssl-tutorial/#comments Sat, 10 Feb 2024 16:25:14 +0000 https://blog.ssdnodes.com/blog/?p=4094 Are you looking for a simple tutorial for how to use Nginx as a reverse proxy with SSL? This guide will walk you through exactly that!

Nginx is a powerful tool. It allows you to serve multiple apps, websites, load-balance applications and much more. All that flexibility is powered by a relatively simple configuration system that uses nearly-human-readable configuration files.

How To Use Nginx as a Reverse Proxy With SSL?

To use Nginx as a reverse proxy with SSL, configure Nginx to listen on the appropriate ports, set up SSL certificates, define proxy_pass directives to forward requests to backend servers, and adjust firewall settings as necessary.

Why Use Nginx as a Reverse Proxy With SSL?

It may not be directly obvious why you might need an Nginx reverse proxy with SSL, but Nginx is a great option for serving your web apps-- take, for example, a NodeJS app.

By default, it runs locally on a machine and listens on a custom-defined port. Usually, this is port 3000 by default and is accessed by typing something like http://YOUR-DOMAIN:3000

But Nginx lets you serve your app that is running on a non-standard port without needing to attach the port number to the URL. It even lets you run different apps on each subdomain, or even in different sub-folders!

Cool, right?

This guide will demonstrate how to utilize Nginx to serve a web app, such as a NodeJS App, using SSL Encryption.

 nginx reverse proxy ssl

Nginx as a Reverse Proxy With SSL - Prerequisites

This guide will assume a general understanding of using a Linux-based system via command line, and will further assume the following prerequisites:

  • Ubuntu 22.04
  • Non-Root User
  • App Running on Custom Port (this guide assumes port 3000)
  • DNS A Name Record for Domain Used
  • SSL Certificate For the Domain

Nginx Configuration

To get the default configuration for Nginx on Ubuntu 22.04, when installed using the Nginx-full package option, look for available sites at the following location:

/etc/nginx/sites-available/

This location will have a default file with an example Nginx virtual host configuration. Instead, we will be creating a new site using an empty file that we can utilize. Once logged in as your non-root user, run the following command to create the new configuration file:

sudo touch /etc/nginx/sites-available/YOUR-DOMAIN

Be sure to replace YOUR-DOMAIN with your domain you plan to associate with your app.

Next, we will modify the file so that it does what we need it to. I will be using vim in this guide, but feel free to use whatever text editor you're most comfortable with:

sudo vim /etc/nginx/sites-available/YOUR-DOMAIN

The next few steps include adjusting the sites-available/YOUR-DOMAIN file you created just before, so be sure to adjust where indicated so that it functions as desired:

This Section tells Nginx to listen on port 80 for your domain and rewrites the request to HTTPS for us

server {
listen 80;
server_name YOUR-DOMAIN www.YOUR-DOMAIN; # Edit this to your domain name
rewrite ^ https://$host$request_uri permanent;
}

This is all the configuration declarations that help SSL Function.

server {
listen 443 ssl;

server_name YOUR-DOMAIN;                                               
# Edit the above _YOUR-DOMAIN_ to your domain name

ssl_certificate /etc/letsencrypt/live/YOUR-DOMAIN/fullchain.pem;       
# If you use Lets Encrypt, you should just need to change the domain. 
# Otherwise, change this to the path to full path to your domains public certificate file.

ssl_certificate_key /etc/letsencrypt/live/YOUR-DOMAIN/privkey.pem;     
# If you use Let's Encrypt, you should just need to change the domain.
# Otherwise, change this to the direct path to your domains private key certificate file.

ssl_session_cache builtin:1000 shared:SSL:10m;                        
# Defining option to share SSL Connection with Passed Proxy

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;                                  
# Defining used protocol versions. 

ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; 
# Defining ciphers to use. 

ssl_prefer_server_ciphers on;                                         
# Enabling ciphers

access_log /var/log/nginx/access.log;                                 
# Log Location. the Nginx User must have R/W permissions. Usually by ownership.

This is the juicy part of the config file, handing off relevant data to our back-end app running on port 3000

Nothing should need to be changed here unless port 3000 is not the port you're using.

Furthermore, if you're using a socket to serve your app (PHP comes to mind), you can define a UNIX:.sock location here as well

location / {
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://localhost:3000;
#proxy_pass unix:/path/to/php7.3.sock # This is an example of how to define a unix socket.
proxy_read_timeout 90;
}

} # Don't leave this out! It "closes" the server block we started this file with. 

Save and exit the YOUR-DOMAIN file. If you're using vim, hit Esc to exit INSERT mode, then type :wq and hit enter to save and exit the file.

To make the file active, we will need to link the file in the sites-available folder to a location within the sites-enabled folder. Again, change YOUR-DOMAIN here with the actual name of the file you created earlier.

ln -s /etc/nginx/sites-avaialable/YOUR-DOMAIN /etc/nginx/sites-enabled/YOUR-DOMAIN.conf

Let's now test the configuration file.

sudo nginx -t

If the test is successful, you'll see this output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Now that we know it's going to work as expected, issue the command to restart the Nginx service

sudo systemctl restart nginx

# OR #

sudo service nginx restart

Both commands perform the same task, simply preference decides your method here. I can safely say I use both and in no specific priority.

You should now be able to launch your app (if it wasn't running already) and visit YOUR-DOMAIN in a browser, assuming the DNS is correct.

Congratulations-- you've now set up a reverse proxy using Nginx. And your app will now be showing to the world with HTTPS enabled!

]]>
https://www.ssdnodes.com/blog/how-to-use-nginx-as-a-reverse-proxy-with-ssl-tutorial/feed/ 1
Nginx Basics — Part 2: Reverse Proxy https://www.ssdnodes.com/blog/nginx-reverse-proxy/ https://www.ssdnodes.com/blog/nginx-reverse-proxy/#respond Mon, 26 Apr 2021 19:47:02 +0000 https://blog.ssdnodes.com/blog/?p=5860 On the web there are basically two types of computers (or more accurately, computer programs). A Server, whose job it is to serve web content. This service may include things like an HTML web page, a dynamic website with user specific contents like Facebook, web apps, or even APIs which programmers can use within other web services, like "Sign In with Google" which is used authenticate users across hundreds of web services. Point is, all of this services are provided what is known as a Server. It is the job of the server to listen for new requests, and give out appropriate response for the requests. Servers are the backbone of the web.

There's another type of program, that is the client. A client sends requests to web servers and gets a response. A client can be your web browser trying to visit a particular website. It can be a Discord App on your desktop talking to Discord servers and enabling you to chat with your friends, and it can even be a command line tools like cURL. If you use Python's request module to talk to a RESTAPI, what you are writing is an HTTP client.

Proxy and Reverse Proxy

A Proxy, in the context of the World Wide Web, means another computer that acts as a client on your behalf. So, a proxy acts as a server that recieves all of the client's HTTP requests, and then it passes those requests onto whatever actual server the request was intended for. This can be used to obfuscate the true origin of the client, to filter out unintended requests in the case of a University or an Organization's network and for a lot of other purposes. A proxy can be used by one or more clients.

A reverse proxy is a proxy for one or more servers, and it acts as a gateway for all the incoming HTTP requests. It ensures that a request reaches its corresponding backend server, and not the wrong one. Of course, it also makes sure that response gets forwarded to the appropriate client as well.

Let's try and configure Nginx to act as a reverse proxy for two web apps.

Nginx reverse proxy

If you need a primer on Nginx Configuration you can follow this blog post. But to start with a Nginx server, we will first get rid of default configuration and start with a custom server directive.

$ rm /etc/nginx/sites-enabled/default

Now, we can start adding configuration for reverse proxy. By default, Nginx will be listening on port 80 and forwarding traffic to relevant endpoints. If you wish to setup HTTPS you can complete the setup here, and then follow the instructions in this blog post.

We basically have two options here:

Both are not that different from Nginx's view point. As long as all these domain names point to the IP address that Nginx is listening on, we combination of them. In fact, we did use them to run multiple websites in blog post.

So to create a reverse proxy, a server directive would create something like this:

server {
    listen 80;
    listen [::]:80;

    server_name example.com;
    location /app1 {
        proxy_pass http://www.example.com/app1
    }
}

The proxy_pass directive tells Nginx to forward requests to the specified URI, and fetch the response and send it back to the appropriate client.

You can create a similar directive for /some/other/path and keep it going untill all your needs are met.

If you have a Python app, called app1 and another NodeJS App called app2 listening on, say, localhost on port 5000 and 5001, you can forward to them simply by using the same location directive like shown below,

location /app1 {
        proxy_pass http://localhost:5000/app1
    }
location /app2 {
        proxy_pass http://localhost:5001/app2
}

Make sure that your apps have root of their routes set at /app1 and /app2, respectively, to make sense of things.

This is how most web applications are developed and deployed. One team of developers can work on /login microservice and use the language of their choice and another can work on /dashboard and use their own framework and backend logic. And Nginx acts as a glue that brings them together in production.

If you want to have a shared hosting environment, where two completely different entities are reverse proxied by Nginx, you can do that too! You just need to create different server directives for each of them. For more details follow this blog post.

Additional configuration options

Having a reverse proxy introduces a few things we need to take care of. First would be that Nginx can become the bottleneck, since all the traffic flows through it. Fortunately, Nginx is very advanced and can handle hundreds, if not, thousands of requests on very minimal hardware. That said, the official docs show us a few decent tuneables like compression, buffering, etc that can help improve the responsiveness of your web service.

One edge case that I have personally seen is where I needed to run Google Analytics on my backend server to track the number of unique visitors. You see, if Nginx is the only 'client' that connects to your backed web app then its IP is the only IP that your web app will always see in the HTTP request headers. This is very easy to fix. We can configure Nginx to pass the client's original IP to the backend server so that the number of unique IPs visiting the website won't be just 1.

location /some/path/ {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://localhost:5000/some/path;
}

Conclusion

That is it! You now know the fundamentals of Nginx reverse proxy and are ready to tackle official docs, configure your own environment and debug your performance issues in real-time!

]]>
https://www.ssdnodes.com/blog/nginx-reverse-proxy/feed/ 0
Nginx Basics – Part 0: Configuration Files https://www.ssdnodes.com/blog/nginx-configuration-files/ https://www.ssdnodes.com/blog/nginx-configuration-files/#respond Mon, 22 Feb 2021 15:15:57 +0000 https://blog.ssdnodes.com/blog/?p=5721 Nginx is one the most useful pieces of software when it comes to the web. It has quickly grown from a simple web server to a fully-featured load balancer, reverse proxy server, and a key component in technologies like Kubernetes as an ingress point. Developers, DevOps and sysadmins all come across its installations in some capacity or the other. So let's dig into what are the various nuts and bolts of a typical Nginx installation. We will focus only on the essential parts of configurations -- The Basics.

TL;DR

A. For Debian and Ubuntu like systems the main configuration files can be found at:

  • /etc/nginx/nginx.conf  where all the main configuration lives. You need not edit this.
  • Directory /etc/nginx/sites-enabled/ with a default file already there for reference

Any custom configuration you wish to add can be added in the directory /etc/nginx/sites-available and you can then create a symlink of that file to the directory /etc/nginx/sites-enabled:

$ sudo ln -s /etc/nginx/sites-available/my-configuration.conf /etc/nginx/sites-enabled
$ sudo systemctl reload nginx

That's the Debian way of doing things. You can also add configurations to /etc/nginx/conf.d/

B. On CentOS, Fedora and RedHat systems:

  • All the default configuration is crammed inside /etc/nginx/nginx.conf
  • For most use cases, the custom configuration will go to /etc/nginx/conf.d with file names ending in .conf 

Setup

To get started you will need the following:

  1. Root access to a VPS with a Public IPv4 address. If you don't already have one, you can get one from SSDNodes.
  2. Ubuntu 20.04 LTS is used as the base operating system. Although, we will discuss the difference between Nginx on different distributions too.

The Default Nginx Setup

Let's install, enable and start Nginx:

$ sudo apt install nginx -y;
$ sudo systemctl enable --now nginx;

By default Nginx will start a simple HTTP server, and serve this default web page:

Nginx Default Webpage

You can view the webpage, by simply typing in the Public IP address of your VPS  in a web browser. The actual webpage might be different for RedHat like distros and Ubuntu, but ultimately it will be a simple html file that Nginx is configured to serve. Which brings us to the next part -- Configuration.

Configuration Files

All the configuration for Nginx lives in the directory /etc/nginx with the /etc/nginx/nginx.conf file at the heart. This is where things get interesting. For the purposes of this blog post, we will ignore various miscellaneous file like in /etc/nginx koi-win, koi-utf, mime.types proxy_params and the rest. For this post, the basics, the files that matter us are:

  1. nginx.conf: The main configuration file of Nginx server
  2. conf.d: The directory where user specific configurations are stored.
  3. site-available and sites-enabled: The directory where user specific configurations are stored for Ubuntu and Debian like systems.

Default nginx.conf

Removing all the comments, for Ubuntu 20.04 the default configuration comes with the following:

nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}

http {

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

sites-enabled/default

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

This is all there is to the man configuration. Each single line ending with a semi-colon is called a directive, in a bit more formal terms:

  1. A Simple Directive consists of the name of that directive name followed by a list of parameters, seperated by spaces, and ends with a semicolon (;).
    For example, the line:

    user www-data;

    Signifies that the Nginx worker process will start as the Unix user www-data and you can modify it to run as any other user that you want it to work as.
    Similarly, other directives like ssl_protocols is followed by a list of TLS protocols that Nginx supports. If you want to remove older versions like TLSv1, simply remove them from the list of parameters and reload nginx by running the command systemctl reload nginx and TLSv1 will no longer be supported. However, I don't recommend fiddling with any of the defaults, unless you really know what you are doing. If you wish to go beyond the basics, the official documentation is always a great place to go.

  2. A Block Directive
    A block directive is made up of the directive name, followed by a pair of curly braces ({}) within which there are multiple single directives. The http block is a really important example for this one, and it is something you will be dealing with a lot. When you are within a block, that block is also called context. So, for example, the lines:

    include /etc/nginx/sites-enabled/*;
    include /etc/nginx/conf.d/*.conf;
    

    Are the directives within the http context. All the user specific configuration that lives in /etc/sites-enabled and /etc/conf.d are brought into the http context, because of the above two lines in nginx.conf.

Difference between RedHat-like systems and Debian like systems:

Debian and Ubuntu

Nginx configuration files are quite modular to begin with. You won't find yourself in need of changing the main configuration file unless you are really fine-tuning something. On Debian and Ubuntu, like systems, this modularity is taken a bit further. All your configuration files live like simple text files in the folder /etc/nginx/sites-available/ and if you want to "enable" a certain configuration you will do so by creating a symlink (a shortcut) of that file to the folder /etc/nginx/sites-enabled:

$ sudo ln -s /etc/nginx/sites-available/my-config /etc/nginx/sites-enabled/my-config

This lets users experiment freely with different configurations. If you need to remove a particular configuration, just remove the symlink from the sites-enabled directory and reload nginx. In fact, even the default file that was shown in the previous section is a symlink and the actual file lives in the sites-available.

There is also conf.d file that allows you to add configurations in a way that works across all distributions. The only difference is that you have to name your files with a .conf extension as specified in the nginx.conf

CentOS, RedHat and Fedora systems

In case of CentOS, RHEL and other similar systems, Nginx gets its user specific configuration mostly from the conf.d subdirectory as decribed by this line in the file nginx.conf in the http context:

include /etc/nginx/conf.d/*.conf;

Configuring a simple static site server

To finish off our tour of Nginx configuration, let's write a configuration that will serve a static website from the directory /var/www/my-web.

Let's create a simple website page:

$ sudo mkdir -p /var/www/my-web
$ cd /var/www/my-web
$ vim index.html

Put the follow contents in the index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Page Title</title>
</head>
<body>
    <h1>This is a Heading</h1>
    <p>This is a paragraph.</p>
</body>
</html>

This isn't much, but it will serve well as an example. You can, of course create a complete static site using software like Hugo.

Next we can add a configuration, instead of going through site-available folders and then creating symlinks, I will just write the server definition in conf.d folder. It will work on all platforms and it is simpler to manage:

$ vim /etc/nginx/conf.d/my-web.conf
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/my-web;
    index index.html index.htm index.nginx-debian.html;
    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

Once the configuration is in place, let's remove the old configuration and reload:

$ sudo rm /etc/sites-enabled/default
$ sudo systemctl reload nginx

If you wish to bring back the original configuration, simply remove my-web.conf file and recreate the symlink for the default config.

Conclusion

If you wish to learn more about Nginx, check out this post detailing how to use it as a reverse proxy endpoint to serve multiple websites. More information about various Nginx directives can be found here.

]]>
https://www.ssdnodes.com/blog/nginx-configuration-files/feed/ 0
Host Multiple Websites On One VPS With Docker And Nginx https://www.ssdnodes.com/blog/host-multiple-websites-docker-nginx/ https://www.ssdnodes.com/blog/host-multiple-websites-docker-nginx/#respond Wed, 17 Apr 2019 16:00:17 +0000 http://ssdnodes.billabailey.com/2017/06/05/tutorial-using-docker-and-nginx-to-host-multiple-websites/ Docker is an excellent tool for running multiple services on a single VPS without them interfering with each other—for example, one website built on WordPress and another built on Ghost or 10 Flat-File Content Managers to Help You Ditch WordPresssome other flat-file CMS. But, containerizing software leads to another problem that confuses many: How do I host multiple websites, each in a separate Docker container, from one VPS? Fortunately, with a little bit of foresight and configuring, you can use Docker and Nginx to host multiple websites from a single VPS.

By default, Docker services all listen on port 80, which would create conflicts for incoming traffic. You can change the listening port, of course, but no one wants to type in coolwebsite.com:34567 to access their favorite site.

What if, instead, you could use nginx to route traffic arriving at coolwebsite.com to a unique to a container listening on the 34567 port, and route traffic arriving to anothercoolwebsite.net a second container listening to 45678?

That's exactly what nginx-proxy does: it listens to port 80 (the standard HTTP port) and forwards incoming requests to the appropriate container. This is often known as a reverse proxy, and takes advantage of Docker's VIRTUAL_HOST variable.

In this tutorial, we'll set up nginx-proxy and learn how to use Docker and Nginx to route traffic to different containers, thereby allowing you to host multiple websites on different domains from a single website.

Prerequisites

Step 1. Starting up nginx-proxy to hook Docker and Nginx together

To get started, let's start up the nginx-proxy container. This can be accomplished either by a single docker command, or using docker-compose. Let's cover both.

To get started, create a Docker network

Before we get started, either way, we need to first create a Docker network that we will use to bridge all of these containers together.

$ docker network create nginx-proxy

From now on, we need to ensure that we're always adding new containers to the nginx-proxy Docker network.

Installing nginx-proxy with Docker

$ docker run -d -p 80:80 --name nginx-proxy --net nginx-proxy -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

Installing nginx-proxy with docker-compose

First, create a new docker-compose.yml file in the directory of your choosing (one titled nginx-proxy is a good idea), and copy in the following text:

version: "3"
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

networks:
  default:
    external:
      name: nginx-proxy

And then run the following docker-compose command to get started.

$ docker-compose up -d

How nginx-proxy works to host multiple websites

As you can see from the code in both options, the container listens on port 80 and exposes the same port inside of the container. That allows all incoming traffic to flow though nginx.

You might be wondering what the /var/run/docker.sock:/tmp/docker.sock line accomplishes. Essentially, this gives any container access to the host's Docker socket, which contains information about a variety of Docker events, such as creating a new container, or shutting one down.

This means that every time you add a container, nginx-proxy sees the event through the socket, automatically creates the configuration file needed to route traffic, and restarts nginx to make the changes available immediately. nginx-proxy looks for containers with the VIRTUAL_HOST variable enabled, so that's critical to our operations moving forward.

Also important to note is the --net nginx-proxy line in the Docker command, and the networks: default: external: name: nginx-proxy block in the docker-compose.yml file. These establish that all containers will communicate over that Docker network.

Step 2. Adding a container to the proxy

Now that we have nginx-proxy running, we can start adding new containers, which will be automatically picked up and configured for. Because we covered it in the last Docker tutorial, and since it's an easy implementation to try out, let's use WordPress as an example.

Using Docker

Starting a WordPress container with a basic configuration is quite easy.

$ docker run -d --name blog --expose 80 --net nginx-proxy -e VIRTUAL_HOST=blog.DOMAIN.TLD wordpress

Take note of a few elements here. --expose 80 will allow traffic to flow into the container on port 80. --net nginx-proxy ensures we're using the Docker network we created earlier. Finally, -e VIRTUAL_HOST=blog.DOMAIN.TLD flags nginx-proxy to create the proxy information and direct traffic arriving to the correct domain.

Using docker-compose

Start by creating a 'docker-compose.yml' file in an empty directory and copying in the following.

version: "3"

services:
   db_node_domain:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: PASSWORD
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: PASSWORD
     container_name: wordpress_db

   wordpress:
     depends_on:
       - db_node_domain
     image: wordpress:latest
     expose:
       - 80
     restart: always
     environment:
       VIRTUAL_HOST: blog.DOMAIN.TLD
       WORDPRESS_DB_HOST: db_node_domain:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: PASSWORD
     container_name: wordpress
volumes:
    db_data:

networks:
  default:
    external:
      name: nginx-proxy

Again, take note of the expose and environment: VIRTUAL_HOST options within the file. Also, the networks option at the bottom is necessary to allow this container to "speak" with nginx-proxy.

Also, take note of the line that begins with db_node_domain. If you are going to host multiple WordPress blogs using this method, you need to create unique database names for each. You should replace db_node_domain with your preferring naming scheme. You also need to update two other fields with this chosen name. First:

depends_on:

  - db_node_domain

And second:

WORDPRESS_DB_HOST: db_node_domain:3306

Once the configuration file is set up, you can run the docker-compose up -d command. As long as your DNS is set up to route traffic properly, things should work correctly.

From here, you can start up any number of additional WordPress site—or any type of service, for that matter—and have them be automatically added to the nginx-proxy network. This Docker and Nginx configuration is pretty infinitely extensible, limited only by the VPS resources available to you.

Additional resources to host multiple websites

Of course, be sure to check out the extensive documentation for nginx-proxy to learn more about how you can configure some more complex proxies between Docker and Nginx, such as those using SSL, with multiple ports, or multiple networks.

We haven't tested it out yet, but there's a "companion" to nginx-proxy called letsencrypt-nginx-proxy-companion that allows for the creation/renewal of Let's Encrypt certificates automatically directly alongside the proxy itself.

Just another example of the really cool things that you can do with Docker!
Thanks much to our sharp-eyed reader John! He pointed out how we can improve our docker-compose files by creating unique database names for each instance of WordPress!

]]>
https://www.ssdnodes.com/blog/host-multiple-websites-docker-nginx/feed/ 0
Hosting multiple SSL-enabled sites with Docker and Nginx https://www.ssdnodes.com/blog/host-multiple-ssl-websites-docker-nginx/ https://www.ssdnodes.com/blog/host-multiple-ssl-websites-docker-nginx/#respond Wed, 22 Nov 2017 06:27:23 +0000 https://blog.ssdnodes.com/blog/?p=1271 In one of our most popular tutorials—Host multiple websites on one VPS with Docker and Nginx—I covered how you can use the nginx-proxy Docker container to host multiple websites or web apps on a single VPS using different containers.

As I was looking to enable HTTPS on some of my self-hosted services recently, I thought it was about time to take that tutorial a step further and show you how to set it up to request Let's Encrypt HTTPS certificates.

With the help of docker-letsencrypt-nginx-proxy-companion (Github), we'll be able to have SSL automatically enabled on any new website or app we deploy with Docker containers.

Prerequisites

  • Any of our OS options—Ubuntu, Debian, or CentOS. Just a note: we've only tested Ubuntu 16.04 as of now.
  • A running Docker installation, plus docker-compose—see our Getting Started with Docker guide for more information.

Step 1. Getting set up, and a quick note

I'm a rather big fan of using docker-compose whenever possible, as it seems to simplify troubleshooting containers that are giving you trouble. Instead of parsing a long terminal command, you can simply edit the docker-compose.yml file, re-run docker-compose up -d, and see the results.

As a result, this tutorial will be heavily biased toward using docker-compose over docker commands, particularly when it comes to setting up the docker-letsencrypt-nginx-proxy-companion service.

If you're interested creating these containers via docker commands, check out the docker-letsencrypt-nginx-proxy-companion documentation.

Already have nginx-proxy set up via our previous tutorial? You can simply overwrite your existing docker-compose.yml file with the file you'll find in Step 2.

If you're just getting started with nginx-proxy, start here. You'll want to start by creating a separate directory to contain your docker-compose.yml file.

$ mkdir nginx-proxy && cd nginx-proxy

Once that's finished, issue the following command to create a unique network for nginx-proxy and other Docker containers to communicate through.

docker network create nginx-proxy

Step 2. Creating the docker-compose.yml file

In the nginx-proxy directory, create a new file named docker-compose.yml and paste in the following text:

version: '3'

services:
  nginx:
    image: nginx:1.13.1
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"

  dockergen:
    image: jwilder/docker-gen:0.7.3
    container_name: nginx-proxy-gen
    depends_on:
      - nginx
    command: -notify-sighup nginx-proxy -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-proxy-le
    depends_on:
      - nginx
      - dockergen
    environment:
      NGINX_PROXY_CONTAINER: nginx-proxy
      NGINX_DOCKER_GEN_CONTAINER: nginx-proxy-gen
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs
      - /var/run/docker.sock:/var/run/docker.sock:ro

volumes:
  conf:
  vhost:
  html:
  certs:

# Do not forget to 'docker network create nginx-proxy' before launch, and to add '--network nginx-proxy' to proxied containers. 

networks:
  default:
    external:
      name: nginx-proxy

Special thanks to Github user buchdag for this all-in-one configuration that works out of the box (most of the time).

After you copy, make sure that the formatting looks the same—the yml parser isn't kind, let's say, to syntax errors.

Now, take a closer look at line 30, which contains - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro. This line creates a Docker volume between a file on your host filesystem (in this case, in the nginx-proxy directory) and a file inside one of the Docker containers. For that volume to work, we need to supply the nginx.tmpl file.

Inside of the nginx-proxy directory, use the following curl command to copy the developer's sample nginx.tmpl file to your VPS.

$ curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > nginx.tmpl

Step 3. Running nginx-proxy for the first time.

If you have an nginx-proxy container running already from the previous tutorial, you'll need to stop it before moving forward.

You can now run the docker-compose command that will kick this all off.

$ docker-compose up -d

The process will start by downloading a few Docker images, and if things finish successfully, the output will end with the following:

Creating nginx-proxy ...
Creating nginx-proxy ... done
Creating nginx-proxy-gen ...
Creating nginx-proxy-gen ... done
Creating nginx-proxy-le ...
Creating nginx-proxy-le ... done

To confirm this, run docker ps. You should see three running containers, named nginx-proxy, nginx-proxy-gen, and nginx-proxy-le, like this:

CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
9ea5fffc24dd        jrcs/letsencrypt-nginx-proxy-companion   "/bin/bash /app/en..."   4 minutes ago       Up 4 minutes                                                   nginx-proxy-le
e2288dfc3c5c        jwilder/docker-gen:0.7.3                 "/usr/local/bin/do..."   4 minutes ago       Up 3 seconds                                                   nginx-proxy-gen
eda8f12bd829        nginx:1.13.1                             "nginx -g 'daemon ..."   4 minutes ago       Up 4 minutes        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   nginx-proxy

If any of those aren't running, you should check their logs. You can do that with docker logs.

$ docker logs nginx-proxy
$ docker logs nginx-proxy-gen
$ docker logs nginx-proxy-le

I've found that most issues arise from nginx-proxy-gen. If you see an error about the nginx-proxy network, try creating the network again with docker network create nginx-proxy. If there are issues with the nginx.tmpl file, double check that it's the same as the one on Github.


If your three containers are running smoothly, then you're ready to start deploying other SSL-enabled containers behind the proxy! At this point, we're shifting away from configuring nginx-proxy and toward the ways, you should configure your apps to run behind it.

Step 4. Set up your DNS

Let's Encrypt will only issue certificates to real domains, not IPs. In order to receive valid certificates, you must set up your DNS correctly. Most likely, you will find your DNS settings with the company from which you bought your domain.

Let's say I want to run Miniflux, a self-hosted RSS reader, on the feeds.example.com domain. In my DNS settings, I would create a new A record that directs feeds.example.com to the public IP of the VPS where I set up my nginx-proxy.

This is not an optional step. Valid, reachable domains are required for SSL to work.

Quick tip: to find your VPSs' public IP, use the following: dig +short myip.opendns.com @resolver1.opendns.com.

Step 5. The configuration basics

In order to set up any containerized app to work with this beautiful proxy we've now set up, you must configure the following:

  • Three environment variables: VIRTUAL_HOST, LETSENCRYPT_HOST, LETSENCRYPT_EMAIL
  • The Docker network (nginx-proxy)
  • Exposing port 80/443

Environment variables

Here are the environment variables:

VIRTUAL_HOST
LETSENCRYPT_HOST
LETSENCRYPT_EMAIL

The VIRTUAL_HOST and LETSENCRYPT_HOST variables will be the same for almost all applications, and will correspond to the domain you used in the previous step to set up DNS.

The LETSENCRYPT_EMAIL variable is self-explanatory: use the email address of your choosing.

Let's extend our example from the last step. Here's the docker-compose settings I would use for that Miniflux installation, given that my email is code>foo@example.com:

environment:
    VIRTUAL_HOST: feeds.example.com
    LETSENCRYPT_HOST: feeds.example.com
    LETSENCRYPT_EMAIL: foo@example.com

Docker network

This will be nginx-proxy, unless you changed it. Here's how it looks in a docker-compose.yml file:

networks:
  default:
    external:
      name: nginx-proxy

Expose port(s)

Any container you create must expose the port on which it listens to traffic. That will be 80, 443, or both. Here's how it looks in a docker-compose.yml file:

expose:
  - 80

A example configuration

And here's how all those different variables and configurations look like in a very basic docker-compose.yml file.

version: '3'

services:
  example-app:
    image: example/example-app
    expose:
      - 80
    environment:
      VIRTUAL_HOST: app.example.com
      LETSENCRYPT_HOST: app.example.com
      LETSENCRYPT_EMAIL: foo@example.com

networks:
    default:
        external:
            name: nginx-proxy

At this point, you should have everything you need to know to deploy all kinds of Docker containers under this SSL-enabled proxy. Let's look at a few examples to show you how it works in the real world.

Leading by example: Miniflux

Remember how I wanted to self-host Miniflux at the feeds.example.com domain? Here's the docker-compose.yml that I came up with. Note the expose, environment, and networks configurations.

version: '2'

services:
  miniflux:
    image: miniflux/miniflux:latest
    expose:
      - 80
    volumes:
      - miniflux_data:/var/www/html/data
    environment:
      VIRTUAL_HOST: feeds.example.com
      LETSENCRYPT_HOST: feeds.example.com
      LETSENCRYPT_EMAIL: foo@example.com

volumes:
  miniflux_data:
        driver: local

networks:
    default:
        external:
            name: nginx-proxy

Initialize the container with docker-compose up -d and you'll have an SSL-enabled feed reader in about 30 seconds!

Leading by example, take 2: WordPress

In my previous tutorial on nginx-proxy, I showed off how easy it is to launch a WordPress instance running behind the proxy.

It's just as easy to do it with SSL. I took the exact same docker-compose.yml file and simply added the LETSENCRYPT_HOST and LETSENCRYPT_EMAIL environment variables. You have to change those two fields according to your needs, in addition to VIRTUAL_HOST.

Take note of the db_node_domain field below. This is where you specify the name of the database that WordPress will connect to. Keep in mind that these names should be unique for each instance of WordPress, and you need to also change the depends_on: and WORDPRESS_DB_HOST: fields accordingly.

version: "3"

services:
   db_node_domain:
     image: mysql:5.7
     volumes:
        - db_data:/var/lib/mysql
     restart: always
     environment:
        MYSQL_ROOT_PASSWORD: somewordpress
        MYSQL_DATABASE: wordpress
        MYSQL_USER: wordpress
        MYSQL_PASSWORD: wordpress
     container_name: wp_test_db

   wordpress:
     depends_on:
        - db_node_domain
     image: wordpress:latest
     expose:
        - 80
     restart: always
     environment:
        VIRTUAL_HOST: blog.example.com
        LETSENCRYPT_HOST: blog.example.com
        LETSENCRYPT_EMAIL: foo@example.com
        WORDPRESS_DB_HOST: db_node_domain:3306
        WORDPRESS_DB_USER: wordpress
        WORDPRESS_DB_PASSWORD: wordpress
     container_name: wp_test
volumes:
  db_data:

networks:
  default:
    external:
      name: nginx-proxy

Run it with docker-compose up -d and then visit your domain—there's that beautiful WordPress installation page with SSL encryption.

Sweet.

Wrapping up

This has been a pretty extensive tutorial, so I understand if you're feeling a little overwhelmed. My goal here isn't to guide you toward any specific end goal, but rather to give you the tools to leverage the fantastic nginx-proxy project to your unique needs.

If you keep the required settings in mind, you should be able to put almost any containerized app behind this proxy. And that gives you a ton of power to get the most out of your VPS.

Best of all, docker-letsencrypt-nginx-proxy-companion will automatically renew your certificates for you, so there's no need to check in or do any manual interventions.

As far as I can tell, this is the best way to serve many, if not dozens of SSL-encrypted websites and apps via a single proxy and a single VPS.

[cta text="Run Docker for $1.11/mo and get 16GB RAM!" text2="You're 90 seconds away from running Docker with multiple websites on SSD Nodes!" button="Start Dockerizing your apps"]

]]>
https://www.ssdnodes.com/blog/host-multiple-ssl-websites-docker-nginx/feed/ 0
Installing Nginx, MySQL, PHP (LEMP) on Ubuntu 16.04 https://www.ssdnodes.com/blog/tutorial-install-lemp-ubuntu/ https://www.ssdnodes.com/blog/tutorial-install-lemp-ubuntu/#respond Mon, 13 Mar 2017 00:00:00 +0000 http://ssdnodes.billabailey.com/2017/03/13/tutorial-installing-nginx-mysql-php-lemp-on-ubuntu-16-04/ A virtual private server (VPS) is most often used to host dynamic websites and applications. This requires installing and configuring a web server.

The LEMP “stack” involves the Linux operating system (L), the Nginx web server (E), a MySQL database (M), and PHP for dynamic webpages (P).

Prerequisites

Before you start, you need the following:

  • A VPS running Ubuntu 16.04
  • A regular (non-root) account with sudo privileges. See our SSH keys tutorial for more information.

Step 1: Disabling apache2

We need to ensure that Apache (a different web server option) isn’t running. Let’s remove it from the server.

sudo apt-get remove apache2
sudo rm /var/www/html/index.html

Step 2: Installing Nginx

Ubuntu’s apt package management software makes installing nginx quite easy. Running the update command ensures you get the most up-to-date version.

sudo apt-get update
sudo apt-get install nginx

Nginx will automatically start running at this point. You can double check this by navigating to the IP address of your VPS via a web browser.

http://remote_server

If successful, you’ll see a default Nginx page.

Step 3: Installing MySQL

Next, we’ll install MySQL, which is a database that will be used to store information. Install this with apt as well.

sudo apt-get install mysql-server

You will be prompted to input a password for the adminisrative user for MySQL. We recommend a strong, secure password. For additional security, you won’t be able to see the characters as you type them in.

Next, run a script to improve the security of the installation.

sudo mysql_secure_installation

You’ll see the following warning about the VALIDATE PASSWORD PLUGIN .

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: 

This plugin will reject passwords that are not strong enough. It’s not necessary if you’re diligent about using strong, secure passwords. If you choose Yes , you’ll be asked to define a policy for strong passwords.

You will also be given an opportunity to change the root password if you’d like.

Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : 

For the remainder of the questions, type in y or Y and then hit Enter . These remove anonymous users and restrict root logins, both of which are best practices.

Step 4: Installing PHP

PHP will be used to serve up dynamic web pages to users as they visit your site. There are other options available, such as Ruby or Node.js, but these fall beyond the scope of this tutorial.

We need to start with installing some programs that help PHP communicate with Nginx and MySQL.

sudo apt-get install php-fpm php-mysql

You need to edit the php.ini file and change one particular line to make the configuration more secure.

sudo nano /etc/php/7.0/fpm/php.ini

You’re looking for a line that begins with ;cgi.fix_pathinfo . To find it easily in nano, type in Ctrl+w and type in cgi.fix_pathinfo . You need to uncomment this line—remove the semicolon—and change the setting to 0 . The end result should look like this:

cgi.fix_pathinfo=0

Once you’ve saved the file, a quick restart of the PHP processor will enable this change.

sudo systemctl restart php7.0-fpm

Step 5: Configuring Nginx and PHP

As we tested earlier, Nginx is already working properly, but it defaults to using HTML to serve up a webpage, not PHP. We need to change that by editing the default Nginx server block.

sudo nano /etc/nginx/sites-available/default

Let’s go step by step through the lines that you will want to edit.

First, you might want to change the root directory of your website, if you’d like to serve it from a different location. The default configuration is perfectly fine, however, so we recommend leaving it alone.

root /var/www/html;

Next, you want to request that Nginx look for an index.php file rather than index.html .

Before:

# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;

After:

# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;

After that, you need to uncomment the area that connects to php-fpm .

Before:

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ .php$ {
#       include snippets/fastcgi-php.conf;
#
#       # With php7.0-cgi alone:
#       fastcgi_pass 127.0.0.1:9000;
#       # With php7.0-fpm:
#       fastcgi_pass unix:/run/php/php7.0-fpm.sock;
#}

After:

location ~ .php$ {
        include snippets/fastcgi-php.conf;

#       # With php7.0-cgi alone:
#       fastcgi_pass 127.0.0.1:9000;
#       # With php7.0-fpm:
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}

Finally, you should restrict access to .htaccess files, which Nginx doesn’t use.

Before:

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /.ht {
#       deny all;
#}

After:

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /.ht {
       deny all;
}

Once you’ve made those three changes, you can save and close the file and test out the configuration.

sudo nginx -t

If you see any errors, check the file for any syntax mistakes you might have made. Once the command returns a positive result, you can restart Nginx to load the new configuration.

sudo systemctl restart nginx

Step 6: Testing PHP

At this point, the LEMP stack should be completely configured, but it doesn’t hurt to take a few extra moments to double-check that it’s running correctly. The easiest way to do that is to create a new file in your document root.

sudo nano /var/www/html/info.php

Inside that file, type or paste in these two lines:

<?php
phpinfo();

Save and close the file, and then visit your website again via a browser.

http://remote_server/info.php

If you see a file like the following, you’re all set up! You’re now ready to host and deploy some serious content to your visitors.

phpinfo.png

In future tutorials, we’ll cover how to add a WordPress installation on top of your LEMP stack, in addition to securing the connection between your server and your visitors with SSL certificates.

 

]]>
https://www.ssdnodes.com/blog/tutorial-install-lemp-ubuntu/feed/ 0