A common way for reliably hosting .NET Core Apps on Linux is to use supervisor to monitor the dotnet
self-hosting processes behind an nginx reverse proxy which handles external HTTP requests to your website and proxies them to the dotnet process running your Web App on a local port. You'll need access to a Unix environment on your client Desktop, either using Linux, OSX or Installing Windows Subsystem for Linux (WSL).
Amazon Linux 2​
Amazon Linux 2 is the next-generation Amazon Linux operating system that provides modern application environment with the latest enhancements from the Linux community and offers long-term support.
It is optimized for use in Amazon EC2 with a latest and tuned Linux kernel version. As a result, many customer workloads perform better on Amazon Linux 2.
We'll start by SSH'ing into your Amazon Linux server, e.g:
ssh -i ~/pem/<my>.pem ec2-user@ec2-<ip-address>.compute-1.amazonaws.com
Install .NET 6.0​
Being based on RHEL you can use yum and the Cent OS 7 Install Instructions to install .NET Core on Amazon Linux 2:
If you just want a minimal ASP.NET Core runtime to run Web Apps you can just install:
sudo yum install aspnetcore-runtime-6.0
But if you'd also like to use dotnet tools like the x super utility you'll need to install the SDK:
sudo yum install dotnet-sdk-6.0
Then install dotnet tools you want which will install under the ec2-user
home directory at ~/.dotnet/tools
:
dotnet tool install --global x
You'll either need to exit & re login to configure the dotnet tool path or you can import it manually with:
. /etc/profile.d/dotnet-cli-tools-bin-path.sh
Where you should now be able be able to run dotnet tools, e.g:
x
Setup the deploy User Account​
We'll then create a dedicated user account for hosting and running your .NET Core Apps to mitigate potential abuse.
Create the deploy
user account with a /home/deploy
home directory and add them to the sudo
group:
sudo useradd -m deploy
Create a password (optional):
sudo passwd deploy
For seamless deployments use visudo
:
sudo visudo
To allow deploy
to run supervisorctl
without prompting for a password:
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
%deploy ALL=(ALL:ALL) NOPASSWD: /usr/bin/supervisorctl
To give sudo
commands access to installed dotnet tools add it to secure_path
:
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/home/ec2-user/.dotnet/tools
Tip
In vi type i
to start editing a file and ESC
to quit edit mode and :wq
to save your changes before exiting
Now we'll create an ~/apps
folder as the deploy
user where your .NET Core Apps should be deployed to, e.g:
sudo su - deploy
mkdir ~/apps
exit
Setup supervisor​
Install supervisor on Amazon Linux 2 by first enabling the EPEL repository:
sudo amazon-linux-extras install epel
Then use yum
to install supervisor
sudo yum install supervisor
You'll also need to create a supervisord.service
systemd script which you can install with:
sudo x mix supervisord.service
Which will write this supervisord.service gist to /usr/lib/systemd/system
.
We'll also want to configure supervisor to look for our *.conf
scripts in the conventional location:
echo 'files = /etc/supervisor/conf.d/*.conf' | sudo tee -a /etc/supervisord.conf
We can then enable & start the systemd supervisord.service with:
sudo systemctl enable supervisord.service
sudo systemctl start supervisord
You'll then need to create a separate config file for each app in /etc/supervisor/conf.d/
.
We can use the same template below by replacing my-app
with the name of your App:
/etc/supervisor/conf.d/app.my-app.conf​
[program:app-my-app]
command=/usr/local/bin/dotnet /home/deploy/apps/my-app/MyApp.dll
directory=/home/deploy/apps/my-app
autostart=true
autorestart=true
stderr_logfile=/var/log/app-my-app.err.log
stdout_logfile=/var/log/app-my-app.out.log
environment=ASPNETCORE_ENVIRONMENT=Production,ASPNETCORE_URLS="http://*:5000/"
user=deploy
stopsignal=INT
We can use x mix to simplify this by downloading & renaming the supervisor
configuration template above:
sudo x mix supervisor -name acme
You can further customize the template by adding any number of -replace term=with
switches, e.g. you can replace the port
with:
sudo x mix supervisor -name acme -replace 5000=5002
Then tell supervisor to register our App configuration:
sudo supervisorctl update
Setup nginx​
Use yum
to install nginx:
sudo yum install nginx
Start nginx​
sudo systemctl start nginx.service
Create Virtual Host Configuration​
You'll also need to create a separate config for each website on nginx in /etc/nginx/conf.d/
. You can use the same template for each website but you'll need to change the server_name with the domain name you want to use for the App and use a different port number for each App:
/etc/nginx/conf.d/my-app.org.conf​
server {
listen 80;
server_name my-app.org;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
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_buffering off;
proxy_ignore_client_abort off;
proxy_intercept_errors on;
client_max_body_size 500m;
}
}
Or use x mix to write the above template using your preferred port and TLD with:
sudo x mix nginx-yum -name acme -replace 5000=5002 -replace org=io
After this we can tell nginx to reload its configuration, as there's nothing listening to http://localhost:5002
yet nginx will return a 502 Bad Gateway response but will start working as soon as our deployed .NET Core Apps are up and running.
sudo nginx -s reload
Setting up SSH keys​
We can now exit our remote Linux server and return to our local machine and prepare our deployment script. Before doing this we recommend setting up SSH and copying your SSH public key to your remote server which is both more secure and more convenient than using a password. You'll want to configure the ~/.ssh/authorized_keys
for your deploy
user account as well as ec2-user
account for convenience.
A manual 'tool-free' solution if you're using WSL is to copy your SSH public key to the clipboard, e.g:
cat ~/.ssh/id_rsa.pub | clip.exe
Then as the deploy
user paste the contents of id_rsa.pub
to /home/deploy/.ssh/authorized_keys
and ensure it has the correct restrictive permissions:
mkdir ~/.ssh
vi ~/.ssh/authorized_keys
# i + paste clipboard + <esc>:wq
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Create the deployment script​
rsync is a beautiful utility that provides a fast, secure file transfer over SSH which you can use to sync the contents of folders to a remote site. There's only 2 commands you need to run to deploy a local .NET Core App remotely, rsync
to sync the published .NET Core App files and supervisorctl
to restart the supervisord
process that runs and monitor the .NET Core App which you can add to a deploy.sh that you can run with WSL bash:
rsync -avz -e 'ssh' bin/Release/net5/publish/ deploy@ec2-<ip-address>.compute-1.amazonaws.com:/home/deploy/apps/acme
ssh deploy@ec2-<ip-address>.compute-1.amazonaws.com "sudo supervisorctl restart app-acme"
To automate the entire deployment down to a single command you can add an npm script to your project's package.json
that creates a production client and server build of your App before running WSL's bash
to run the deploy script. All Webpack Single Page App Templates already have a publish npm script, so you would just need to add a deploy script to run publish before running the above deploy.sh
{
"publish": "dotnet publish -c Release",
"deploy": "npm run publish && bash deploy.sh",
}
Now to deploy your App you can just run:
npm run deploy
Which deploys your published App to your remote Linux server instance using rsync
to only copy the incremental parts of the App that's changed (typically completing in <1s) and ssh
to run a remote command to restart the suprvisord
process, starting the .NET Core App with the latest deployed version.
After you deploy your and restart your supervisor
Service your .NET Core App should now be publicly available at your chosen domain, if you have issues
you can view your App's error log for info, e.g:
tail -n 50 /var/log/app-[my-app].err.log
Setup Lets Encrypt​
If you're configuring an Internet Website you'll also likely want to configure it to use SSL, the easiest & free way is to use letsencrypt.org which you can install with:
sudo yum install certbot python2-certbot-nginx
Then use certbot
to automatically configure the domains you want to configure to use SSL, e.g:
sudo certbot -d acme.io -d www.acme.io
Now you're .NET Core creation should be accessible via https://
& the shiny new secure badge in the users Browsers URL.