This is a step-by-step guide on how to configure Nginx on Ubuntu Server to run a single or multiple ASP.NET Core APIs on one domain (no subdomain).
This post is quite extensive so let's break into steps to achieve this:
First of all we need Nginx installed on the server. We can use apt-get
to install.
sudo apt-get install nginx
After the installation the web server should already be up and running. To check the status of the Nginx run the following command:
sudo systemctl status nginx
After install Nginx you may need to open HTTP or HTTPS ports in the firewall. If you are using Amazon EC2 (like me) just use the AWS Management Console to do this and you are ready to go to the next topic.
Let's list the application configurations that ufw
knows how to work with:
sudo ufw app list
There are three profiles available for Nginx to open the ports 80 (HTTP) and port 443 (HTTPS):
Lets run the following command to enable the Nginx Full profile.
sudo ufw allow 'Nginx Full'
Now let's run the following command to verify the change:
sudo ufw status
The following configuration is what I'm using and should be enough to get started. In case you are interesting in details, the Nginx documentation is a good place for reference and also devdocs.io/nginx.
Create the /etc/nginx/proxy.conf
configuration file with the content:
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
large_client_header_buffers 4 16k;
Modify the file /etc/nginx/nginx.conf
and replace the content with the following:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.config;
events {
worker_connections 1024;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
types_hash_max_size 2048;
keepalive_timeout 30;
server_tokens off;
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.config;
include /etc/nginx/sites-enabled/*;
include /etc/nginx/proxy.config;
default_type application/octet-stream;
log_format custom '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for" $request_id ';
access_log /var/log/nginx/access.log custom;
error_log /var/log/nginx/error.log;
}
Edit the default server block to handle unmatched server_name
by returning the status code of 444 (connection closed without response). Modify the default Nginx server block /etc/nginx/sites-available/default
and replace the content with the following:
server {
listen 80 default_server;
listen [::]:80 default_server;
return 444;
}
Test the Nginx configuration for correct syntax:
sudo nginx -t
If there are no errors, restart Nginx.
sudo systemctl restart nginx
First let's create a folder to the domain (e.g. example.com) within directory /var/www
using the -p
flag to create any necessary parent directories:
sudo mkdir -p /var/www/example.com
Next, to avoid any permission issues, make the Nginx user www-data
owner of the directory that we just created:
sudo chown -R www-data: /var/www/example.com
Allow the owner and groups to write to the directory:
sudo chmod -R 775 /var/www/example.com
Add another user to the www-data
group if you need to (e.g. ubuntu user of the Amazon EC2):
sudo usermod -a -G www-data ubuntu
Now let's create the server block (a configuration file) /etc/nginx/sites-available/example.com
with the following content:
server {
listen 80;
listen [::]:80;
server_name example.com *.example.com;
location / {
return 200 "OK";
}
}
To enable the new server block it is needed to create a symbolic link from the file in sites-available
directory to the sites-enabled
directory, which is read by Nginx during startup:
sudo ln -sfn /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
Then test the configuration syntax and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
Now you should get the text "OK" when accessing http://example.com in your browser.
Basically we need to configure the ASP.NET Core API as a service and configure the Nginx as a reverse proxy. The Microsoft documentation help me a lot.
During this process the following configuration files will be created or edited:
/etc/systemd/system/my-example-api.service:
Service unit configuration file for the ASP.NET Core API./etc/nginx/proxy.conf:
Proxy configuration file./etc/nginx/nginx.conf:
Nginx configuration file./etc/nginx/sites-available/default:
Default server block./etc/nginx/sites-available/example.com:
Domain server block.Nginx isn't set up to manage the Kestrel process. Therefore, systemd
can be used to create a service file to command (start, stop or restart) and monitor the API.
Create the service unit configuration file:
sudo vim /etc/systemd/system/my-example-api.service
The following is an example service configuration file for the My Example API (if necessary, change to suit your use case):
[Unit]
Description=My Example API
[Service]
WorkingDirectory=/var/www/example-api/current
ExecStart=/usr/bin/dotnet /var/www/example-api/current/ExampleAPI.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=my-example-api
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://localhost:5000
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
EnvironmentFile=/path/to/file.conf
[Install]
WantedBy=multi-user.target
Start the service and verify that it's running.
sudo systemctl start my-example-api.service
sudo systemctl status my-example-api.service
Once the API that is running on Kestrel is managed by systemd
, all events and processes are logged to the journal (a systemd
component). To view the my-example-api.service
records, use the following command:
sudo journalctl -fu my-example-api.service
For filtering by time to reduce the amount of records returned:
sudo journalctl -fu my-example-api.service --since "2019-01-01" --until "2019-01-20 06:00"
It is needed to configure Nginx as a reverse proxy to forward requests made to http://example.com on to the ASP.NET Core API running on Kestrel at http://localhost:5000. Modify the server block /etc/nginx/sites-available/example.com
and replace the content with the following:
server {
listen 80;
listen [::]:80;
server_name example.com *.example.com;
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
}
Then test the configuration syntax and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
The API will be available at http://example.com.
We will configure Nginx as a reverse proxy to forward requests to multiple ASP.NET Core APIs by using the rewrite
directive. Modify /etc/nginx/sites-available/example.com
and replace the content with the following:
server {
listen 80;
listen [::]:80;
server_name example.com *.example.com;
location /myapi1 {
rewrite /myapi1/?(.*) /$1 break;
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
location /myapi2 {
rewrite /myapi2/?(.*) /$1 break;
proxy_pass http://localhost:5010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
}
You will need to have one service configuration file for each API to run both APIs as a service. Just repeat the step already described in this post paying attention to the paths and port used.
Then test the configuration syntax and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
Now both APIs myapi1
and myapi2
will be available on the same server at http://example.com/myapi1 and http://example.com/myapi2 respectively.