Introduction
There once was a time where C# application could only run on the Windows operating system. This is no longer that time. Since the release of .NET Core, the power of these applications (and their treasure trove of libraries & frameworks) can be put to use on Linux systems.
One of the most refreshing things about this advancement is that it’s now possible to decouple the software and the underlying infrastructure. This has seemed out of reach for a very long time!
We’ll use NGINX to proxy requests from the outside world into the Kestrel server that is likely to be bundled with your application. We do this because Kestrel is not a real web-scale web server, rather just a container for your application to run inside. NGINX however is very good at managing larger scales of traffic.
In fact, here’s Microsoft’s appraisal of Kestrel:
Kestrel is great for serving dynamic content from ASP.NET, however the web serving parts aren’t as feature rich as full-featured servers like IIS, Apache or Nginx. A reverse proxy-server can allow you to offload work like serving static content, caching requests, compressing requests, and SSL termination from the HTTP server. The reverse proxy server may reside on a dedicated machine or may be deployed alongside an HTTP server.
What you’ll need
- A C# .NET Core application
- An Ubuntu 16.04 server on your cloud provider of choice (I use DigitalOcean)
- Access to the server over SSH – ideally you’ll have a non root user. I have included the sudo prefix for commands that need it
- Familiarity with the command line
Let’s get started!
Create your Deployable
Before you configure your server, let’s get your project in a deployable state. Head over to the directory where your .sln or .csproj file and run the following command to compile your project to a selection of .dlls – don’t worry, these run on Linux now!
$ dotnet publish -c Release --output ./published
Now, test the application on your computer. Run the following command to test it, substituting MyApplication.dll
for your actual paths:
$ dotnet MyApplication.dll
Navigate to http://localhost:<port>
in your browser and behold your application. If all is well, proceed to the next step.
Copy the files to the server
There are a couple of ways to achieve this. The easiest method is to copy everything that has been generated as part of the dotnet publish command to your target server using an FTP client. I recommend putting the files in your server user’s home directory for now, as it makes it a little easier to find again later.
You can also do this with SCP, which you can run from the command line:
$ scp -r ./published <user>@<server-ip>:/home/<user>/app
Hopefully you have all of your files up on your server now, and we can move on to the next step!
Configure .NET Core
Let’s get .NET Core installed on your server. Enter the following commands into your terminal after having logged into your server over SSH:
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
sudo apt-get update
sudo apt-get install dotnet-dev-1.0.4
(These instructions assume you’re running Ubuntu 16.04 and want to install .NET Core 1.0.4. See this folder for more installation instructions!)
Now you’re ready to configure your web server!
Configure NGINX
As mentioned, we’ll use NGINX to proxy requests into our application. Let’s install and configure NGINX now. After you’ve logged onto your server, execute the following command:
$ sudo apt-get install nginx
This will install NGINX and set up some default configuration files. We need to customise the configuration. Let’s do that now. I use pico for file editing on Linux servers, but if you’re more comfortable with VIM, use vi instead.
$ sudo pico /etc/nginx/sites-enabled/default
This’ll open the default NGINX configuration. Delete everything in the file (it’ll be fine, promise!) and paste the following lines:
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;
}
}
There’s a fair bit going on here – essentially what this config does is listen for HTTP requests on port 80, and proxy them into your .NET Core application running on port 5000. If you’re not using that port, be sure to update this configuration to reflect your choice!
Restart NGINX to load your new configuration:
$ sudo service nginx restart
Now, let’s make sure your application runs forever!
Set up systemd to monitor your application
Ubuntu comes with an amazing little tool called systemd that basically watches a given process (in this case, it’s your application) and can keep it running. For it to do so, we need to set up a “service definition” that describes your application and tells the system how to watch it.
Let’s set up that config now:
$ sudo pico /etc/systemd/system/dotnet-core-app.service
(Feel free to call that file something else, but for simplicity I’m giving it a generic name here)
Paste the following lines, substituting the appropriate values:
[Unit]
Description=My first .NET Core application on Ubuntu
[Service]
WorkingDirectory=/home/user/app
ExecStart=/usr/bin/dotnet /home/user/app/MyApp.dll
Restart=always
RestartSec=10 # Restart service after 10 seconds if dotnet service crashes
SyslogIdentifier=dotnet-core-app
User=user
Environment=ASPNETCORE_ENVIRONMENT=Production
[Install]
WantedBy=multi-user.target
Now, save the file, and enable our new service:
$ sudo systemctl enable dotnet-core-app.service
We’re ready to start the service! Let’s do that now:
$ sudo systemctl start dotnet-core-app.service
Let’s check this started properly, enter the following command:
$ sudo systemctl status dotnet-core-app.service
You should see something like this:
● dotnet-core-app.service - My first .NET Core application on Ubuntu
Loaded: loaded (/etc/systemd/system/dotnet-core-app.service; enabled)
Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet) CGroup: /system.slice/dotnet-core-app.service
└─9021 /usr/local/bin/dotnet /home/user/app/MyApp.dll
Now, let’s check if all of this worked! Open up your server URL in a browser, you should see your application!
Conclusion
If all went to plan, you should see your shiny .NET Core application running on Ubuntu! Who’d have thought it?
Something not working? Let me know in the comments and I’ll do my best to help you out! Enjoy!