Deploy ASP.NET web app to a Linux virtual machine in Azure
Tags: dotnet, csharp, azure, linux
Published: 2021-08-19 20:51:50

Hey, there! It's a pleasure to be able to greet you. In this new article we will learn step by step how to deploy our web applications with ASP.NET (with a DotVVM project as an example) on an Ubuntu Server 20.04 virtual machine under the concept infrastructure as a service in Microsoft Azure. 

Given these considerations, here are the important points that we will review in this tutorial article: 

+ Create a virtual machine with a Linux distribution in Azure. 
+ Install the .NET environment and an Apache server on the virtual machine.
+ Publish the ASP.NET web application in Visual Studio 2019. 
+ Host the web application on the virtual machine.
+ Plus: Attach a database to the virtual machine. 

##Part 1: Create a virtual machine with a Linux distribution in Azure

To start, we must have a subscription in Azure, if we do not have an account we can get a free one here: [https://azure.microsoft.com/free/](https://azure.microsoft.com/free/).

As a first step, we need to go to the Azure portal and find the Virtual Machines resource and create a new one. In the creation process we will have several important parts for the creation of the resource. Each of these parts is detailed below. 

####**Generals** 

To begin with, you need to specify the subscription and resource group, then the details of the instance to create. This is where we will define the operating system that the virtual machine will have and the size of it. For our goals, we will work with Ubuntu Server 20.04.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yuspph61xu7qeof0d756.png)

Then we need to define the virtual machine administrator account information through the username and password. This data is very important as it will allow us to access the virtual machine later. For this purpose we have two options, either generate an *SSH public key*, or set an access password. For this case, we will select the password option and we will have something like this:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gq22smbh0o8zveaz3cpt.png)

Finally, in the general section we can define rules for the ports of the virtual machine. In this case we will enable port 80 for HTTP connections that will allow access to the website from the internet browser. The other port is SSH (22), which will allow us to access the virtual machine remotely.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mq8a3hlewwzs914utuoa.png)

####**Specifics**

Once you have specified the general aspects, you can perform a general review of the parameters set and create the resource. In another scenario, we can also specify in detail the disk configuration for the virtual machine, whether ssd or HDD type, network configuration and load balancing, management and extension management. 

Once these configurations are complete and the creation process has begun, this operation will take a few minutes to execute. 

With the resource ready, we can now go to the main section of the resource in Azure and get the public IP address assigned to our VM.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/euvht4aiucac988xxcca.png)

If this is the case, in the configuration of the public IP we can establish that this IP address is static, that is, that the address does not change at the time of restarting the virtual machine. On the other hand, we can also establish a DNS for this public IP address.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybfmf4g8dm81a9r9w3mz.png)

##Part 2: Install the .NET environment and an Apache server on the virtual machine

Now that we have the virtual machine with Ubuntu Server 20.04 set in Azure, we will connect remotely via the SSH (Secure SHell) protocol through the command console. 

In this case, we'll run the following command with the username (set at the time the VM was created in Azure), followed by the IP address or DNS:

```shell
ssh azureuser@40.77.109.26
```

Here we will have to enter our access credentials:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcfhqk9teo5pczomgw5i.png)

####**.NET Installation**

All right, to get started we'll install the .NET SDK. Installation with APT can be done with a few commands. Before installing .NET, we need to add the Microsoft package signing key to the list of trusted keys and add the package repository.

```shell
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb

sudo dpkg -i packages-microsoft-prod.deb
```

When you install the .NET SDK, you do not need to install the corresponding runtime environment. To install the .NET SDK, we must run the following commands:

```shell
sudo apt-get update
sudo apt-get install -y apt-transport-https
sudo apt-get update
sudo apt-get install -y dotnet-sdk-5.0
```

With this process, we will already have .NET installed on our virtual machine. To perform a verification of the installed SDK, we can enter the following command:

```shell
dotnet --version
```

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzbjxrt119p53ja0glux.png)

####**Apache Installation**

To expose our application to the internet, we need IIS (Internet Information Services), Nginx, or Apache as a reverse proxy server that accepts the HTTP request and forwards it to Kestrel (a web server that is included and enabled by default in the ASP.NET project templates).
 
Given these considerations, we must enter the following command to install Apache:

```shell
sudo apt-get install apache2
```

Considering that port 80 of the virtual machine is open, now we can copy the public IP or DNS and run it in the browser, if apache is installed correctly, we can display the default apache page:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib7v6oopxgjfoyygyuad.png)

Now, we need to enable Apache's *modproxy* modules so that it can function as a reverse proxy:

```console
systemctl restart apache2
a2enmod proxy proxy_http proxy_html
```

##Part 3: Publish the web application with ASP.NET in Visual Studio 2019 

Up to this point, the machine with Ubuntu Server 20.04 on Azure is with all the required components. From this point on, we'll start with the process of deploying a web application to the .NET virtual machine.

To exemplify this scenario, we will deploy a web application with the DotVVM framework, based on the MVVM (Model, View, ViewModel) pattern on ASP.NET 5. 

The first thing we will do is go to our solution in Visual Studio 2019 to select the main project (in this case with DotVVM) in .NET, and click on the `Publish` button:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hokngoiuhoaarrqi7ut3.png)

In the dialog box that is displayed, we will create a new publishing profile of type Folder, and specify the path where we want our files to be deployed:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4xoaamwdf56jcumayvl.png)

Finally, we will publish our solution from the profile created:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kgm69z0isqzr1wxq3odz.png)

When finished, our files will have been deployed in the previously specified folder:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dcsciu54r43xzyv4oevk.png)

We will use these files in the next step within the virtual machine.

##Part 4: Host the web application on the virtual machine

####**Configure the Apache server**

All configuration files in Apache are stored in the `/etc/apache2/conf-enabled` directory. Back to our virtual machine via an SSH connection, we will need to create a `.conf` file for our web application. We can do this by opening the nano text editor as follows:

```shell
sudo nano /etc/apache2/conf-enabled/DotNetApp.conf
```

***Note:*** the name of the file may be what we want to specify. 

In `DotNetApp.conf`, we will insert the following content:

```html
<VirtualHost *:80>  
   ProxyPreserveHost On  
   ProxyPass / http://127.0.0.1:5000/  
   ProxyPassReverse / http://127.0.0.1:5000/  
   ErrorLog /var/log/apache2/DotNetApp-error.log  
   CustomLog /var/log/apache2/DotNetApp-access.log common  
</VirtualHost>
```

In .NET, web applications by the command console run by default on port 5000, in case we wanted our application to run on another port, we can specify the execution port in the `webBuilder` within the `Program.cs` class of our project as follows:

```csharp
.UseUrls("http://*:8080")
```

Also, in the configuration file `DotNetApp.conf` we are indicating that our application can be accessed from port 80. If this is the case, we could change the port, however, it is important to remember to enable the port in question from the virtual machine settings in Azure.

####**Copy the application files to the virtual machine**

What we have to do now is configure our web application so that it can be accessed from port 80. In this sense, what we will do at this time is to copy the files previously deployed in Visual Studio 2019 to the virtual machine. We will do this from the `/var/` directory:

```shell
cd /var/
sudo mkdir DotNetApp
```

Now, we will have to perform the file transfer. From Windows, we can use the *WinSCP* program to connect to the virtual machine and perform this process.

***WinSCP Installer:*** [https://winscp.net/eng/download.php](https://winscp.net/eng/download.php).

Once *WinSCP* is installed and initialized, we will create a new session with the credentials of our Azure virtual machine:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g3ui2s69alcv8hyf9xcg.png)

With this connection, in the user by default we can create a new folder, for example, App, and in it copy the files of our application:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0e0xni9ami7wl84n19km.png)

Now all the files have been uploaded to the VM, in the next step, we need to move the files from the `/home/azureuser/App` directory to the `/var/DotNetApp` directory:

```shell
cd /home/azureuser/App
sudo cp -R * /var/DotNetApp/
```

With this process, our web application is already hosted on the virtual machine as such:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8kocm69rb5eqisk8heb.png)

####**Create a service to start and monitor the web application.**

To create this service file that will allow us to launch our web application, we will open the nano editor:

```shell
sudo nano /etc/systemd/system/kestrel-DotNetApp.service
```

In this file, we will add the following content to provide the working directory and which file must be run to get the web application up and running.

```conf
[Unit]  
Description=Aspnet 5 Web App running on Ubuntu  
[Service]  
WorkingDirectory=/var/DotNetApp  
ExecStart=/usr/bin/dotnet /var/DotNetApp/UserDashboard.dll  
Restart=always  
RestartSec=10  
SyslogIdentifier=dotnet-demo  
User=www-data  
Environment=ASPNETCORE_ENVIRONMENT=Production  
[Install]  
WantedBy=multi-user.target  
```

Now, we'll enable and start the created service:

```shell
sudo systemctl enable kestrel-DotNetApp.service  
sudo systemctl start kestrel-DotNetApp.service
```

With the *status* attribute we can check the status of the service:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ei7vqc0g0xd4zdhkb0vw.png)

Finally we can restart the Apache server and see that our application is running from port 80 as well:

```shell
systemctl restart apache2 
sudo service apache2 restart
```

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ap8o8z8wfgmr8tti9wud.png)

Now that the hosting and all the corresponding settings have been made, we can now access the browser using the assigned public IP, or DNS name, and see our web application ASP.NET with DotVVM running correctly on top of the Linux VM on Azure.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuhhhtbmeah2y6tetx5l.png)

##Plus: Attach a database to the virtual machine 

Up to this point, we have already deployed our application, however, most (if not all) web projects are associated with a database. In this case, let's look at an example on how to install a PostgreSQL database inside the virtual machine, and associate it with our project with DotVVM in ASP.NET 5. 

To install PostgreSQL we will type the following command:

```shell
sudo apt install postgresql postgresql-contrib
```

Then, it is necessary within the configuration of the virtual machine in Azure to enable port 5432 to access PostgreSQL remotely.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tletenxjyshgkuvaxha6.png)

Now, in Ubuntu Server we must modify the file `pg_hba.conf` to allow connections to PostgreSQL remotely: 

```shell
sudo nano /etc/postgresql/12/main/pg_hba.conf
```

Inside the `pg_hba.conf` file, in the *IPv4 local connections* section we will leave the corresponding statement as follows:

```conf
# IPv4 local connections:
host    all             all             all            md5
```

The last file that we will have to modify is called: `postgresql.conf`. This configuration will be used to set the IP addresses that can be connected to PostgreSQL remotely:

```shell
sudo nano /etc/postgresql/12/main/postgresql.conf
```

In the *Connections and Authentication* section, we will remove the # symbol and we will be left with the following statement:

```conf
listen_addresses = '*'
```

Finally, we must restart the database service:

```shell
sudo service postgresql restart
```

With these settings we can already set a user to access the database, this could be an example:

```console
sudo -u postgres psql

CREATE USER admin PASSWORD 'Abc#1234'
ALTER ROLE admin WITH SUPERUSER;
```

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qea0tqxnyou6w3nfckds.png)

Then, we only have to make the corresponding configurations in our database. To do this we can connect remotely with the user we just created:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvk8qifkr66x7hc1okdv.png)

Finally, according to our example, in the web application we should establish this new connection to the database.

```
host=localhost;port=5432;Username=admin;Password=Abc#1234;Database=postgres
```

To reflect these changes in production, we need to replace the files or file with the new configuration in `/var/DotNetApp`, and restart the associated services (*Kestrel* and *Apache*).

##What's next? 

With this article we have everything step by step how to deploy a web application with ASP.NET 5 and DotVVM from Visual Studio 2019 to a virtual machine with Ubuntu Server 20.04 on Azure. Here are additional resources so you can continue to learn about developing apps with .NET and azure: 

+ [Deploying ASP.NET Core web applications to a Windows Server VM in Azure](https://dev.to/dotvvm/deploying-asp-net-core-and-dotvvm-web-applications-to-a-virtual-machine-in-azure-230f).

+ [.NET 5: Deploying web apps with Azure App Service](https://dev.to/esdanielgomez/net-5-deploying-web-apps-with-azure-app-service-5349).

+ [Building a Dashboard with ASP.NET Core and DotVVM](https://dev.to/esdanielgomez/building-a-dashboard-with-asp-net-core-and-dotvvm-349).

####**Thanks for reading**

Thank you very much for reading, I hope you found this article interesting and may be useful in the future. If you have any questions or ideas that you need to discuss, it will be a pleasure to be able to collaborate and exchange knowledge together.

See you on [Twitter](https://twitter.com/esDanielGomez)! Or if you like you can also write to me on [Instagram](https://instagram.com/esdanielgomez) or on [Telegram](https://t.me/esdanielgomez). :=)