Hostování ASP.NET Core na Linuxu s Nginx
26.10.2020
Článek popisuje, jak nastavit ASP.NET Core na Linuxu.
Cílem je z Linuxu vytvořit webový server, na kterém může běžet webová stránka napsaná v programovacím jazyce C#.
Jde o proof of concept, kdy mě zajímalo, jak moc je složité nastavit Linux spolu s Nginx jako alternativu k IIS.
Nastavení se dá použít pro vývojové nebo testovací prostředí, případně jako podklad pro produkci,
pokud bychom chtěli hostovat stránky na VPS nebo on-premises serveru.
Slovníček
ASP.NET Core | Open-source webový framework od Microsoftu, poprvé vydaný v roce 2016. |
Kestrel | Odlehčený, multiplatformní webový server od Microsoftu, který je součástí frameworku ASP.NET Core. |
Nginx | Původem ruský webový server, na kterém běží přibližně třetina webových stránek na internetu. |
IIS | Webový server od Microsoftu s podporou .NET |
VMware Player | VMware Workstation Player je zdarma dostupná aplikace (pro nekomerční použití), která slouží k správě a spouštění virtuálních strojů. |
Reverzní proxy | Proxy server na straně serveru, nikoliv klienta, který přeposílá požadavky klienta na další servery. Může také sloužit například k load balancingu, kešování, zabezpečení, šifrování a podobně. |
Bridged network | Síťová konfigurace, která propojuje virtuální počítač (VM) s fyzickou sítí prostřednictvím hostitelského počítače. |
Obsah
- Příprava prostředí
- Konfigurace NGINX serveru
- Vytvoření a publikování ASP.NET Core projektu
- Vyzkoušení funkčnosti
- Odkazy
Příprava prostředí
Idea je znázorněná obrázkem a jedná se o velmi jednoduchý scénář, který vyžaduje pouze jeden počítač (s procesorem, který podporuje virtualizaci). Na počítači se nainstaluje nějaký "virtualizér", v mém případě VMware Player, ale je možné použít i VirtualBox nebo Hyper-V. Virtuální počítač připojíme do lokální sítě (bridge network) a nainstalujeme Linux (Ubuntu). V Linuxu nainstalujeme .NET Core runtime a také webový server Nginx, který nastavíme tak, aby veškeré HTTP/HTTPS požadavky přesměrovával na Kestrel, jehož odpověď nám pak Nginx přepošle zpět (reverse proxy).
Instalace Linuxu
Stáhneme si instalační .ISO pro Ubuntu (v mém případě verze Desktop 20.04.1 LTS) Nastavíme VMware Player do bridge módu a nainstalujeme Linux standardním způsobem.
Instalace .NET Core
Nyní nainstalujeme .NET Core runtime, verze musí být kompatibilní s verzí, ve které pak poběží web, který budeme hostovat. Jelikož budu na serveru web přímo i vytvářet, tak musím dodatečně nainstalovat i SDK (Software Development Kit).sudo apt update
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update; \
sudo apt-get install -y apt-transport-https && \
sudo apt-get update && \
sudo apt-get install -y aspnetcore-runtime-3.1
sudo apt-get update; \
sudo apt-get install -y apt-transport-https && \
sudo apt-get update && \
sudo apt-get install -y dotnet-sdk-3.1
dotnet --list-runtimes
dotnet --list-sdks
Instalace Nginx
Nginx nainstalujeme jednoduše následujícím příkazem :-)sudo apt install nginx
Konfigurace Nginx serveru
Nginx může hostovat více stránek, každá stránka má pak vlastní konfigurační soubor (tzv. block, což je obdoba virutal hostu v Apache). V adresáři /etc/nginx/sites-available/ vytvoříme tedy konfigurační soubor pro náš web, který jsem pojmenoval pracovně CoreSampleWeb.cz.
/etc/nginx/sites-available/coresampleweb.cz
server {
listen *:80;
server_name CoreSampleWeb.cz
return 301 https://$host$request_uri;
}
server {
listen *:443 ssl;
server_name CoreSampleWeb.cz;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# ssl_stapling on; #ensure your cert is capable
# ssl_stapling_verify on; #ensure your cert is capable
# Enabling HSTS, (max-age in seconds fo 2 years)
# The first time your site is accessed using HTTPS and it returns the Strict-Transport-Security header,
# the browser records this information, so that future attempts to load the site using HTTP will automatically use HTTPS instead.
# It helps to prevent MITM attack.
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
# X-Frame-Options allows content publishers to prevent their own content from being used in an invisible frame by attackers.
# The DENY option is the most secure, preventing any use of the current page in a frame. More commonly, SAMEORIGIN is used,
# as it does enable the use of frames, but limits them to the current domain.
# This option is related to frame and iframe (inline frame) html tag.
# The method exploiting this vulnerability is called clickjacking.
add_header X-Frame-Options DENY;
# 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".
# https://www.keycdn.com/support/what-is-mime-sniffing
add_header X-Content-Type-Options nosniff;
# Add client IP to the header address chain
# https://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Add information about client protocol to the header
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
proxy_set_header X-Forwarded-Proto $scheme;
# Other settings, related to optimalization and web socket (SignalR)
# 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;
# Redirects all traffic
location / {
proxy_pass http://localhost:5000;
# limit_req zone=one burst=10 nodelay;
}
}
sudo nginx -t
sudo nginx -s reload
V konfiguraci je nastaveno několik důležitých věcí
- Všechny HTTP požadavky s doménovým jménem coresampleweb.cz přeposíláme na HTTPS
- Všechny HTTPS požadavky s doménovým jménem coresampleweb.cz přeposíláme na http://localhost:5000
- Veřejný SSL klíč je uložený v souboru /etc/ssl/certs/nginx-selfsigned.crt
- Privátní SSL klíč je uložený v souboru /etc/ssl/private/nginx-selfsigned.key
- Nastavili jsme HSTS pomocí hlavičky Strict-Transport-Security
- Zablokovali jsme clickjacking pomocí hlavičky X-Frame-Options
- Zablokovali jsme MIME-sniffing pomocí hlavičky X-Content-Type-Options
- Nastavili jsme hlavičky X-Forwarded-For a X-Forwarded-Proto, které může web aplikace využít
Vygenerování SSL certifikátu
Do úložiště klíčů si vygenerujeme privátní a veřejný klíč. Takový klíč se bude zobrazovat v prohlížeči uživatele jako nedůvěryhodný, protože nebyl podepsán certifikační autoritou, ale to nám pro testovací účely nevadí.sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt
Správa služby
Pro ovládání Nginx služby můžeme použít příkaz systemctl.# Enable or disable Nginx to start automatically when the server boots
sudo systemctl enable nginx
sudo systemctl disable nginx
# Start, stop, restart or reload service
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx
# Check status of the service
sudo systemctl status nginx
Vytvoření a publikování ASP.NET Core projektu
Z důvodu jednoduchosti aplikaci vytvořím přímo na linuxovém serveru, jinak je samozřejmě možné aplikaci přesunout přes sdílený disk, usb, ftps apod. Vytvořím si tedy v domovském adresáři složku workspace.mkdir -p ~/workspace/CoreSampleWeb
cd ~/workspace/CoreSampleWeb
dotnet new mvc
- Přidáme podporu pro ForwardedHeaders
- Zakomentujeme app.UseHttpsRedirection(), protože HTTPS již řešíme na úrovni Nginxu
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseForwardedHeaders();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseForwardedHeaders();
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
dotnet publish --configuration release
sudo rm -rf /var/www/CoreSampleWeb/*
sudo cp -r ~/workspace/CoreSampleWeb/bin/Release/netcoreapp3.1/publish/* /var/www/CoreSampleWeb/
dotnet CoreSampleWeb.dll

127.0.0.1 CoreSampleWeb.cz
Vyzkoušení funkčnosti
Nyní máme již téměř vše nastaveno, pro HTTP/S službu vytvoříme na firewallu pravidlo a zkusíme se připojit z nějakého počítače v lokální síti.
Nastavení firewallu
Zkontrolujeme a nastavíme firewall, abychom se mohli na stránku připojit i mimo server. K tomu použijeme příkaz ufw, který na pozadí nastavuje iptablessudo ufw enable
sudo ufw allow 80
sudo ufw allow 443
sudo ufw status
sudo apt install net-tools
ifconfig
sudo service network-manager restart
Připojení z klienta
Před tím, než zadáme adresu našeho webu do prohlížeče, musíme nastavit DNS záznam. Pod oprávněním administrátorského účtu otevřeme notepad a upravíme soubor C:\Windows\System32\drivers\etc\hosts, kde 192.168.0.178 je adresa Linux serveru.192.168.0.178 CoreSampleWeb.cz
