Deploying a .NET Core 2.0 Web Application to a Production Environment on Ubuntu 16.04 using Nginx

The goal of this blog is to take you step-by-step through the deployment of a .NET Core 2.0 web application on a Ubuntu 16.04 Production environment.

I’m writing this because I discovered the hard way that .NET Core’s ‘dotnet run’ command is NOT meant to be production ready. My biggest headache was that my website shut down when I exited my shell. Not even the ‘disown’ command would dissociate the running service from the user.

I needed to find a way to start my .NET Core project and have it STAY running. Nginx and Kestrel was where my research led me.


  • You already have a .Net Core 2.0 project that builds and runs properly.

I personally use Linode to spin up my Linux distros because of their $5/month instance. Excellent for developers just playing around and learning new things.

All the steps (Just the “what” for now)

Here we go. Spin up a brand new Ubuntu 16.04 instance and open up a terminal window.

The [USERNAME], [PUBLISH_DIRECTORY], and [SERVICE_NAME] are meant to be replaced by you.

1.  Create new user
adduser [USERNAME]
2.  Change the password again. This enables FTP access for the new account
passwd [USERNAME]
3.  Grant sudo privileges to the new user
usermod -aG sudo [USERNAME]
4.  Switch to the new user
5.  Disable the root account
sudo passwd -l root
6.  Add the 'dotnet' repository link
sudo sh -c 'echo "deb [arch=amd64] xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
7.  Update the apt-get feed
sudo apt-get update
8.  Install .NET Core 2.0
sudo apt-get install dotnet-sdk-2.0.0
9.  Install Git
sudo apt-get install git
10. Install NPM (if your project relies on NPM to build or publish)
curl -sL | sudo -E bash -
sudo apt-get install npm
11. Give new user permissions to use NPM
sudo chown -R $USER:$(id -gn $USER) /home/[USERNAME]/.config
12. Install Nginx
sudo apt-get install nginx
13. Create the Nginx reverse proxy settings.
sudo nano /etc/nginx/sites-available/default
     Erase all existing contents and replace with the following. I'm assuming that your project runs on port 5000 by default. Modify your proxy pass as necessary.
     server {
listen 80;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
     Verify the syntax of the nginx settings with the following
     sudo nginx -t
14. Place the raw unpublished project files in "/home/[USERNAME]/website" directory. You can accomplish this with either FTP or Git. You may omit the /bin, /obj, and /node_modules folder to save copy time. They are re-created when the solution is published.
15. Publish the project to [PUBLISH_DIRECTORY]
dotnet publish -c Release -o [PUBLISH_DIRECTORY]
16. Create the kestrel service definition file.
sudo nano /etc/systemd/system/[SERVICE_NAME].service
     Enter the following into the new service definition file (case sensitive).
Description=Example .NET Web API Application running on Ubuntu
ExecStart=/usr/bin/dotnet [PUBLISH_DIRECTORY]/[PROJECTNAME].dll
17. Enable your new service to auto-start on system boot.
sudo systemctl enable [SERVICE_NAME].service
18. Reboot the system.
19. Verify that your service is running without error.
sudo systemctl status [SERVICE_NAME].service

Port 80 is open to the public by default. And we declared in the Nginx reverse proxy that your project is routed from port 5000 to port 80.

Congratulations! You should now be able to see your project running from your server’s IP address!