AspNetCore.Docs/aspnetcore/host-and-deploy/linux-nginx.md

307 lines
12 KiB
Markdown
Raw Normal View History

---
title: Host ASP.NET Core on Linux with nginx
description: Describes how to setup nginx as a reverse proxy on Ubuntu 16.04 to forward HTTP traffic to an ASP.NET Core web app running on Kestrel.
2016-10-29 01:35:15 +08:00
author: rick-anderson
ms.author: riande
manager: wpickett
ms.custom: mvc
2017-08-24 23:35:33 +08:00
ms.date: 08/21/2017
2016-10-29 01:35:15 +08:00
ms.topic: article
2016-11-17 08:24:57 +08:00
ms.technology: aspnet
ms.prod: asp.net-core
uid: host-and-deploy/linux-nginx
2016-10-29 01:35:15 +08:00
---
# Host ASP.NET Core on Linux with nginx
2016-10-29 01:35:15 +08:00
By [Sourabh Shirhatti](https://twitter.com/sshirhatti)
2017-08-24 23:35:33 +08:00
This guide explains setting up a production-ready ASP.NET Core environment on an Ubuntu 16.04 Server.
2017-03-21 00:40:33 +08:00
**Note:** For Ubuntu 14.04, *supervisord* is recommended as a solution for monitoring the Kestrel process. *systemd* isn't available on Ubuntu 14.04. [See previous version of this document](https://github.com/aspnet/Docs/blob/e9c1419175c4dd7e152df3746ba1df5935aaafd5/aspnetcore/publishing/linuxproduction.md)
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
This guide:
2016-10-29 01:35:15 +08:00
* Places an existing ASP.NET Core app behind a reverse proxy server.
* Sets up the reverse proxy server to forward requests to the Kestrel web server.
* Ensures the web app runs on startup as a daemon.
* Configures a process management tool to help restart the web app.
2016-10-29 01:35:15 +08:00
## Prerequisites
2017-08-24 23:35:33 +08:00
1. Access to an Ubuntu 16.04 Server with a standard user account with sudo privilege
1. An existing ASP.NET Core app
2016-10-29 01:35:15 +08:00
## Copy over the app
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Run `dotnet publish` from the dev environment to package an app into a self-contained directory that can run on the server.
2016-10-29 01:35:15 +08:00
Copy the ASP.NET Core app to the server using whatever tool integrates into the organization's workflow (for example, SCP, FTP). Test the app, for example:
* From the command line, run `dotnet <app_assembly>.dll`.
* In a browser, navigate to `http://<serveraddress>:<port>` to verify the app works on Linux.
2016-10-29 01:35:15 +08:00
## Configure a reverse proxy server
A reverse proxy is a common setup for serving dynamic web apps. A reverse proxy terminates the HTTP request and forwards it to the ASP.NET Core app.
2017-08-24 23:35:33 +08:00
### Why use a reverse proxy server?
2016-10-29 01:35:15 +08:00
Kestrel is great for serving dynamic content from ASP.NET Core; however, the web serving parts arent as feature rich as servers like IIS, Apache, or nginx. A reverse proxy server can offload work like serving static content, caching requests, compressing requests, and SSL termination from the HTTP server. A reverse proxy server may reside on a dedicated machine or may be deployed alongside an HTTP server.
2016-10-29 01:35:15 +08:00
For the purposes of this guide, a single instance of nginx is used. It runs on the same server, alongside the HTTP server. Based on requirements, a different setup may be choosen.
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Because requests are forwarded by reverse proxy, use the `ForwardedHeaders` middleware from the `Microsoft.AspNetCore.HttpOverrides` package. This middleware updates `Request.Scheme`, using the `X-Forwarded-Proto` header, so that redirect URIs and other security policies work correctly.
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
When setting up a reverse proxy server, the authentication middleware needs `UseForwardedHeaders` to run first. This ordering ensures that the authentication middleware can consume the affected values and generate correct redirect URIs.
2016-11-30 08:06:06 +08:00
2017-08-24 23:35:33 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x)
2016-11-30 09:17:22 +08:00
2017-08-24 23:35:33 +08:00
Invoke the `UseForwardedHeaders` method (in the `Configure` method of *Startup.cs*) before calling `UseAuthentication` or similar authentication scheme middleware:
2016-11-30 09:17:22 +08:00
```csharp
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
2017-08-24 23:35:33 +08:00
app.UseAuthentication();
2016-11-30 09:17:22 +08:00
```
2017-08-24 23:35:33 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x)
Invoke the `UseForwardedHeaders` method (in the `Configure` method of *Startup.cs*) before calling `UseIdentity` and `UseFacebookAuthentication` or similar authentication scheme middleware:
```csharp
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseIdentity();
app.UseFacebookAuthentication(new FacebookOptions()
{
AppId = Configuration["Authentication:Facebook:AppId"],
AppSecret = Configuration["Authentication:Facebook:AppSecret"]
});
```
---
### Install nginx
2016-10-29 01:35:15 +08:00
```bash
2016-10-29 01:35:15 +08:00
sudo apt-get install nginx
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
> [!NOTE]
> If optional nginx modules will be installed, building nginx from source might be required.
2016-10-29 01:35:15 +08:00
Use `apt-get` to install nginx. The installer creates a System V init script that runs nginx as daemon on system startup. Since nginx was installed for the first time, explicitly start it by running:
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```bash
2016-10-29 01:35:15 +08:00
sudo service nginx start
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
Verify a browser displays the default landing page for nginx.
2016-10-29 01:35:15 +08:00
### Configure nginx
2016-10-29 01:35:15 +08:00
To configure nginx as a reverse proxy to forward requests to our ASP.NET Core app, modify `/etc/nginx/sites-available/default`. Open it in a text editor, and replace the contents with the following:
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```nginx
2016-10-29 01:35:15 +08:00
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 $http_host;
2016-10-29 01:35:15 +08:00
proxy_cache_bypass $http_upgrade;
}
}
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
This nginx configuration file forwards incoming public traffic from port `80` to port `5000`.
2016-10-29 01:35:15 +08:00
Once the nginx configuration is established, run `sudo nginx -t` to verify the syntax of the configuration files. If the configuration file test is successful, force nginx to pick up the changes by running `sudo nginx -s reload`.
2016-10-29 01:35:15 +08:00
## Monitoring the app
2016-10-29 01:35:15 +08:00
The server is setup to forward requests made to `http://<serveraddress>:80` on to the ASP.NET Core app running on Kestrel at `http://127.0.0.1:5000`. However, nginx is not set up to manage the Kestrel process. *systemd* can be used to create a service file to start and monitor the underlying web app. *systemd* is an init system that provides many powerful features for starting, stopping, and managing processes.
2016-10-29 01:35:15 +08:00
### Create the service file
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Create the service definition file:
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```bash
sudo nano /etc/systemd/system/kestrel-hellomvc.service
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
The following is an example service file for the app:
2016-10-29 01:35:15 +08:00
```ini
[Unit]
Description=Example .NET Web API App running on Ubuntu
[Service]
WorkingDirectory=/var/aspnetcore/hellomvc
ExecStart=/usr/bin/dotnet /var/aspnetcore/hellomvc/hellomvc.dll
Restart=always
RestartSec=10 # Restart service after 10 seconds if dotnet service crashes
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
**Note:** If the user *www-data* is not used by the configuration, the user defined here must be created first and given proper ownership for files.
**Note:** Linux has a case-sensitive file system. Setting ASPNETCORE_ENVIRONMENT to "Production" results in searching for the configuration file *appsettings.Production.json*, not *appsettings.production.json*.
2016-10-29 01:35:15 +08:00
Save the file and enable the service.
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```bash
systemctl enable kestrel-hellomvc.service
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
Start the service and verify that it is running.
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```
systemctl start kestrel-hellomvc.service
systemctl status kestrel-hellomvc.service
● kestrel-hellomvc.service - Example .NET Web API App running on Ubuntu
Loaded: loaded (/etc/systemd/system/kestrel-hellomvc.service; enabled)
Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
CGroup: /system.slice/kestrel-hellomvc.service
└─9021 /usr/local/bin/dotnet /var/aspnetcore/hellomvc/hellomvc.dll
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
With the reverse proxy configured and Kestrel managed through systemd, the web app is fully configured and can be accessed from a browser on the local machine at `http://localhost`. It is also accessible from a remote machine, barring any firewall that might be blocking. Inspecting the response headers, the `Server` header shows the ASP.NET Core app being served by Kestrel.
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```text
HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
### Viewing logs
2016-10-29 01:35:15 +08:00
Since the web app using Kestrel is managed using `systemd`, all events and processes are logged to a centralized journal. However, this journal includes all entries for all services and processes managed by `systemd`. To view the `kestrel-hellomvc.service`-specific items, use the following command:
2016-11-18 13:03:07 +08:00
```bash
sudo journalctl -fu kestrel-hellomvc.service
2016-11-18 13:03:07 +08:00
```
For further filtering, time options such as `--since today`, `--until 1 hour ago` or a combination of these can reduce the amount of entries returned.
2016-11-18 13:03:07 +08:00
```bash
sudo journalctl -fu kestrel-hellomvc.service --since "2016-10-18" --until "2016-10-18 04:00"
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
## Securing the app
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
### Enable AppArmor
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Linux Security Modules (LSM) is a framework that is part of the Linux kernel since Linux 2.6. LSM supports different implementations of security modules. [AppArmor](https://wiki.ubuntu.com/AppArmor) is a LSM that implements a Mandatory Access Control system which allows confining the program to a limited set of resources. Ensure AppArmor is enabled and properly configured.
2016-10-29 01:35:15 +08:00
### Configuring the firewall
2016-10-29 01:35:15 +08:00
Close off all external ports that are not in use. Uncomplicated firewall (ufw) provides a front end for `iptables` by providing a command line interface for configuring the firewall. Verify that `ufw` is configured to allow traffic on any ports needed.
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```bash
2016-10-29 01:35:15 +08:00
sudo apt-get install ufw
sudo ufw enable
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
### Securing nginx
2016-10-29 01:35:15 +08:00
The default distribution of nginx doesn't enable SSL. To enable additional security features, build from source.
2016-10-29 01:35:15 +08:00
#### Download the source and install the build dependencies
2016-11-18 13:03:07 +08:00
```bash
2016-10-29 01:35:15 +08:00
# Install the build dependencies
sudo apt-get update
sudo apt-get install build-essential zlib1g-dev libpcre3-dev libssl-dev libxslt1-dev libxml2-dev libgd2-xpm-dev libgeoip-dev libgoogle-perftools-dev libperl-dev
# Download nginx 1.10.0 or latest
wget http://www.nginx.org/download/nginx-1.10.0.tar.gz
tar zxf nginx-1.10.0.tar.gz
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
#### Change the nginx response name
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Edit *src/http/ngx_http_header_filter_module.c*:
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```c
static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
#### Configure the options and build
2017-08-24 23:35:33 +08:00
The PCRE library is required for regular expressions. Regular expressions are used in the location directive for the ngx_http_rewrite_module. The http_ssl_module adds HTTPS protocol support.
2016-10-29 01:35:15 +08:00
Consider using a web app firewall like *ModSecurity* to harden the app.
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```bash
2016-10-29 01:35:15 +08:00
./configure
--with-pcre=../pcre-8.38
--with-zlib=../zlib-1.2.8
--with-http_ssl_module
--with-stream
--with-mail=dynamic
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
#### Configure SSL
* Configure the server to listen to HTTPS traffic on port `443` by specifying a valid certificate issued by a trusted Certificate Authority (CA).
2016-10-29 01:35:15 +08:00
* Harden the security by employing some of the practices depicted in the following */etc/nginx/nginx.conf* file. Examples include choosing a stronger cipher and redirecting all traffic over HTTP to HTTPS.
2016-10-29 01:35:15 +08:00
* Adding an `HTTP Strict-Transport-Security` (HSTS) header ensures all subsequent requests made by the client are over HTTPS only.
* Do not add the Strict-Transport-Security header or chose an appropriate `max-age` if SSL will be disabled in the future.
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Add the */etc/nginx/proxy.conf* configuration file:
2016-10-29 01:35:15 +08:00
[!code-nginx[Main](linux-nginx/proxy.conf)]
2016-10-29 01:35:15 +08:00
2017-08-24 23:35:33 +08:00
Edit the */etc/nginx/nginx.conf* configuration file. The example contains both `http` and `server` sections in one configuration file.
2016-10-29 01:35:15 +08:00
[!code-nginx[Main](linux-nginx/nginx.conf?highlight=2)]
#### Secure nginx from clickjacking
Clickjacking is a malicious technique to collect an infected user's clicks. Clickjacking tricks the victim (visitor) into clicking on an infected site. Use X-FRAME-OPTIONS to secure the site.
2017-08-24 23:35:33 +08:00
Edit the *nginx.conf* file:
2016-11-18 13:03:07 +08:00
```bash
sudo nano /etc/nginx/nginx.conf
2016-11-18 13:03:07 +08:00
```
Add the line `add_header X-Frame-Options "SAMEORIGIN";` and save the file, then restart nginx.
#### MIME-type sniffing
2017-08-24 23:35:33 +08:00
This header prevents most browsers from MIME-sniffing a response away from the declared content type, as the header instructs the browser not to override the response content type. With the `nosniff` option, if the server says the content is "text/html", the browser renders it as "text/html".
2017-08-24 23:35:33 +08:00
Edit the *nginx.conf* file:
2016-11-18 13:03:07 +08:00
```bash
sudo nano /etc/nginx/nginx.conf
2016-11-18 13:03:07 +08:00
```
Add the line `add_header X-Content-Type-Options "nosniff";` and save the file, then restart nginx.