×
Community Blog Deploying Multiple Web Apps on Simple Application Server with SSL Certificates

Deploying Multiple Web Apps on Simple Application Server with SSL Certificates

In this guide, we will be deploying 2 Node.js apps and 1 ASP.NET core app on a single Simple Application Server and secure everything with SSL to enable HTTPS.

By Arnab Choudhuri, Alibaba Cloud Community Blog author

This article is meant for individual developers or startups with developers who are not very familiar with deployments and are currently using PaaS solutions for the same. In this article, we look at the steps one has to do to deploy multiple web applications on a single server using Alibaba Cloud's Simple Application Server.

In most cases a single server has enough resources and can run multiple web applications. A user might have, say, two web applications/websites connecting two domains abc.com and xyz.com or even abc.com and a subdomain api.abc.com. In such circumstances both, or all three of the applications, can be run from the same server using the technique shown in this article. Also, it is considered best practice to secure sites with SSL certificates. We will secure our applications and their respective domains with free valid Let's Encrypt SSL certificates.

This is a continuation from my previous articles Developing ASP.NET Core App in Visual Studio and Deploying on Simple Application Server and Developing Node.js App in Visual Studio and Deploying on Simple Application Server.

Developing Example Applications

Node.js Application

Develop two Node.js applications named NodejsApp1 and NodejsApp2.

Most information is available in the article Developing Node.js App in Visual Studio and Deploying on Simple Application Server.

Please ensure that both the applications work at different ports.

To ensure the same go to app.js in one application you have..

app.set('port', process.env.PORT || 3000);

And in the other application you have..

app.set('port', process.env.PORT || 3010);

ASP.NET Core Application

Develop an asp.net core application and publish the same as a self-contained application.

Most information is available in the article Developing ASP.NET Core App in Visual Studio and Deploying on Simple Application Server.

While using Kestrel, which is the web server that's included by default in ASP.NET Core project templates, port 5000 is used on default behavior.

It is a good practice to explicitly state the host address and port the webhost will listen on or use a wildcard instead resulting in the web host binding to all IPv4 and IPv6 IPs addresses on specified port via the UseUrls(...) extension method that's available on the IWebHostBuilder interface.

In the Program.cs file, edit the CreateWebHostBuilder method to add UseUrls extension as shown below.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://*:5000")
                .UseStartup<Startup>();

If you are deploying more than one asp.net core applications, do use two different ports say 6000 and 6010.

Deploy Applications on Simple Application Server

Create a Simple Application Server Instance on Alibaba Cloud

Follow my previous articles to do this step.

Create Non-Root User Account with sudo Privileges

Open a terminal window using putty and login as root to server.

Create a new user account using the adduser command (I here choose name mysudouser which you are free to replace with the user name that you want to create).

adduser mysudouser

Use the passwd command to set a password for the new user

passwd mysudouser

You will be prompted to confirm the password. Ensure you use a strong password.

Add the new user to the wheel group.

usermod -aG wheel mysudouser

Note: By default, on CentOS, members of the wheel group have sudo privileges.

Switch to the newly created user

su – mysudouser

00

Note: The first time you use sudo from this account, you will be prompted to enter the password for this user account.

Install Prerequisites on Server

Complete the following steps to install prerequisites for node.js applications. Please go through the node.js article to understand more on the commands.

yum -y update

sudo yum install curl

sudo yum install epel-release

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
sudo yum -y install nodejs
sudo yum install gcc-c++ make
node -v

The last command verifies the installation of node.js and provides its version as output.

The asp.net core article explains how to publish your application as self-contained and as such does not require any prerequisites or framework installation.

Our three applications are running on ports 3000, 3010 and 5000. To open these ports on the server..

Go back to the Server management screen on AlibabaCloud Console and select the option Firewall under Security.

Click on button Add Rules and add a firewall rule as shown in image below.

01

Deploy Application

There are multiple ways of moving published application files to the server including the usage of FTP Client. We will use Filezilla. To install Filezilla for free visit https://filezilla-project.org/

In Filezilla, Select File > SiteManager

Select sFTP as Protocol

Add server ip address as Host, 22 as Port and Normal as Logon Type

Add root as User , Password as the one you set earlier and select Connect

Once logged in, create three directories (we named dotnetapp, expressapp1 and expressapp2) and drag and drop publish folder in case of asp.net core app and the two node.js app in the same.

02

Run Applications on Server

In the putty terminal screen, move inside the folder where the published files are uploaded (in our case dotnetapp/publish)

Run our application now with the following commands:

chmod +x alibabadotnetcore
./alibabadotnetcore

Now, you should see an output showing the application is running properly. If you check on your browser with server_ip_address:port_number (port number=5000), you should see the application running.

Now without closing this terminal screen, open a new putty terminal screen and log in.

Move inside the folder, where first Node.js application code is uploaded (in our case /expressapp1).

Run our application now with the following commands:

npm install
npm start

Now, you should see output to show the application is running properly. If you check on browser with server_ip_address:port_number (port number=3000), you should see the application running.

Again, without closing this terminal screen, open a new putty terminal screen (this will be the third terminal) and log in.

Move inside the folder, where second Node.js application code is uploaded (in our case /expressapp2).

Run our application now with the following commands:

npm install
npm start

Now, you should see output to show the application is running properly. If you check on browser with server_ip_address:port_number (port number=3010), you should see the application running.

Link Domain Names to the Applications

Alibaba Cloud Domains

In case one has bought a domain name from Alibaba Cloud, the linking is very simple.

Go back to the Server management screen on the Alibaba Cloud Console and select the option Domains under Website.

Select Add Domain Name

Now resolve your domain name with this Simple Application Server

03

Now you should see your three applications by accessing domain_name:port_number in the browser (eg. abc.com:3000 should show the first node.js application if you own abc.com domain name).

3rd Party Domains

In case one owns a domain name via a 3rd party provider, one would need to change the A Record in DNS configuration in Domain provider's console and link it to the public IP Address of Simple Application Server. Please connect with the help line of your domain name provider if you need hand holding in such cases.

04

05

06

Once all the domain names are connected to the simple application server, you should be able to view any of the three applications from all the three domains.

Our next task is to ensure that we do not view all the applications from all the domains but one application under each domain. We would achieve this using Nginx.

Nginx is a web server which can act as a reverse proxy. A reverse proxy server can offload work such as serving static content, caching requests, compressing requests, and SSL termination from the HTTP server.

But we already have three terminals open and we would have to open another terminal to install and configure Nginx.

Or we need to ensure our applications run without the necessity of keeping the terminals open. This is what we would do next using Supervisor.

Running Applications with Supervisor

Close the second and third terminals running node.js applications and in the first terminal shut down the asp.net core application by pressing Ctrl +C

Install Prerequisites on Server

GNU nano is a small and friendly text editor useful for editing configuration files.

sudo yum update
sudo yum install nano

When it asks if this is OK[y/d/N]: y

Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems.

sudo yum update
sudo yum install supervisor

When it asks if this is OK[y/d/N]: y

Working with Supervisor

Copy all application files from home folder to /var folder

cd  /
cp -r dotnetapp /var
cp -r expressapp1 /var
cp -r expressapp2 /var

To the supervisor configuration file we add the following settings info

Add a program name using [program:nodejsapp1]

Set a working directory using directory=/var/expressapp1/ExpressApp1

Add the command to run using command=npm start --production

Enable autostarting using autostart=true

Enable autorestart using autorestart=true

Add an error log file using stderr_logfile=/var/expressapp1/nodejsapp1.err.log

Add a normal log file using stdout_logfile=/var/expressapp1/nodejsapp1.out.log

Node.js Applications

Now we edit the supervisor configuration file

nano /etc/supervisord.conf

And add at the end of the file the following lines

[program:nodejsapp1]

directory=/var/expressapp1/ExpressApp1
command=npm start --production
autostart=true
autorestart=true
stderr_logfile=/var/expressapp1/nodejsapp1.err.log
stdout_logfile=/var/expressapp1/nodejsapp1.out.log

[program:nodejsapp2]

directory=/var/expressapp2/ExpressApp2
command=npm start --production
autostart=true
autorestart=true
stderr_logfile=/var/expressapp2/nodejsapp2.err.log
stdout_logfile=/var/expressapp2/nodejsapp2.out.log

Asp.net core Application

Please go through the previous asp.net core article for this. It has a detailed writeup explaining the whole concept including creation of startup scripts.

Save and run supervisor by following command

sudo supervisord -c /etc/supervisord.conf

Now again you should be able to view any of the three applications from all the three domains by accessing domain_name:port_number in the browser (eg. abc.com:3000 should show the first node.js application if you own abc.com domain name).

Reverse Proxy using Nginx

Install

sudo yum install nginx

When it asks if this is OK[y/d/N]: y

Start the Nginx service using the below command

sudo service nginx start

Check to ensure Nginx was setup properly.

systemctl status nginx

Now, hitting Nginx from the public IP assigned to your server or any of your domain names should show the welcome screen.

Configure

The configuration file for nginx exists at /etc/nginx/nginx.conf

We could change this file as we have done in the previous asp.net core article.

But it is better to create three separate files for three separate domains and applications with the name formatted as abc.com.conf. Later sites which are to be disabled can be named abc.com.conf.disabled.

We would do this at location /etc/nginx/conf.d/

This is because nginx.conf contains the following line which looks for configuration files at the above location.

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

Create three configuration files in the below format (if domain abc.com and configuration file abc.com.conf)

server {
    listen 80;
    listen [::]:80;
    server_name abc.com www.abc.com;

    location /
    {
        proxy_pass http://127.0.0.1:3000;
    }
}

Do note to change the domain name and port number.

Note: Do study configuration examples of Nginx at https://www.nginx.com/resources/wiki/start/topics/examples/full/

Specially the proxy.conf section and server_names_hash_bucket_size under http block. Depending on the complexities in your application, you may need to add them.

Once done, Ensure your Nginx configuration changes checkout as valid syntax.

sudo nginx –t

Reload Nginx

sudo nginx -s reload

Now the applications can be accessed from the respective domains without the port number.

Note: What happens if you link a domain name to the server but do not add it to the server block in the configuration files? Nginx configuration file has a default route which takes that domain and shows it the Nginx home page on the server.

Securing with Let's Encrypt SSL certificates

Let's Encrypt is the Certificate Authority (CA) which provides free SSL certificate.

Let's Encrypt uses the ACME protocol to verify that you control a given domain name and to issue you a certificate. To get a Let's Encrypt certificate, you'll need to choose a piece of ACME client software to use, amongst which CERTBOT is recommended.

To obtain an SSL certificate, install the certbot software on your server. The best way to install this is through the EPEL repository which we have already installed.

Install

Obtain the certbot package

sudo yum install certbot 

Test whether the client is working correctly.

certbot –help

It throws an error ImportError: No module named 'requests.packages.urllib3'

Note: In case later you do not find any error, please skip the next section and jump to configure section.

Handling error

Remove the package and reinstall.

sudo rm -rf /usr/lib/python2.7/site-packages/urllib3
sudo yum install python-urllib3
sudo yum update
sudo yum clean all
sudo rm -r /var/cache/yum
sudo yum update

Test whether the client is working correctly.

certbot –help

Now, the problem is sorted.

Configure

Even though CERTBOT enables auto installation and configuration of nginx, I suggest you take the following path which will help you to know what is happening in your production servers and enable you to change, upgrade your configurations if you need.

Create the webroot folder.

sudo mkdir -p /var/www/letsencrypt/.well-known
sudo chgrp nginx /var/www/letsencrypt
sudo chmod g+s /var/www/letsencrypt

Create an nginx configuration file

sudo mkdir /etc/nginx/letsencrypt/
sudo nano -w /etc/nginx/letsencrypt/webroot.conf

Include the webroot path

location ^~ /.well-known/acme-challenge/ {
  allow all;
  root /var/www/letsencrypt/;
  default_type "text/plain";
  try_files $uri =404;
}

Create a file

sudo nano -w /etc/nginx/letsencrypt/ssl.conf

And add some ssl configuration

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";

Note: Ensure that the text after ssl_ciphers is in a single line in ssl.conf file.

Note: Follow the below instructions for all the three domains and their corresponding applications one after the other to secure all of them.

Add the webroot.conf to your nginx domain configuration file eg. abc.com.conf

sudo nano /etc/nginx/conf.d/abc.com.conf
server {
    listen 80;
    listen [::]:80;
    server_name abc.com www.abc.com;
    include letsencrypt/webroot.conf;

    location /
    {
        proxy_pass http://127.0.0.1:3000;
    }
}

Restart nginx

sudo systemctl restart nginx

Request the certificate from Let's Encrypt with certbot with a valid email id.

sudo certbot certonly --verbose --email admin@abc.com --agree-tos --webroot -w /var/www/letsencrypt/ -d abc.com -d www.abc.com
/etc/letsencrypt/live/abc.com/ folder gets created and certificate as well as chain file gets generated and placed in the folder.

Now go back to the nginx configuration file abc.com.conf and do the following

  • force non-https URI to https
  • install the certificate
  • force www to non www
sudo nano /etc/nginx/conf.d/abc.com.conf

server {
listen 80;
listen [::]:80;
server_name abc.com www.abc.com;
include letsencrypt/webroot.conf;
return 301 https://$host$request_uri;
  location /
  {
     proxy_pass http://127.0.0.1:3000;
  }
}
server {
listen 443 ssl;
server_name abc.com;

ssl_certificate /etc/letsencrypt/live/abc.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/abc.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/abc.com/chain.pem;
include letsencrypt/ssl.conf;
include letsencrypt/webroot.conf;
location /
{
     proxy_pass http://127.0.0.1:3000;
     }
}

server {
listen 443 ssl;
server_name www.abc.com;

ssl_certificate /etc/letsencrypt/live/abc.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/abc.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/abc.com/chain.pem;
include letsencrypt/ssl.conf;
include letsencrypt/webroot.conf;
 
return 301 https://abc.com$request_uri;
location /
{
     proxy_pass http://127.0.0.1:3000;
    }
}

Restart nginx

sudo systemctl restart nginx

Test using the Qualys SSL Labs Report to see how your server configuration scores https://www.ssllabs.com/ssltest/analyze.html

Now, access abc.com or www.abc.com and reach http://abc.com

Note: There are a few other things which you might wish to do such as to increase security, generate a strong Diffie-Hellman group and auto renew the certificates which lapse after 90 days. There are sufficient articles available in the web to help you with them.

Conclusion

These are the basic steps one has to do to deploy multiple diverse applications and secure them on Alibaba Cloud Simple Application Server with CentOS.

0 0 0
Share on

Alibaba Clouder

2,599 posts | 762 followers

You may also like

Comments