Hostování ASP.NET Core na Linuxu
26.10.2020
Článek popisuje jak zprovoznit 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 jazyce C#.
Jde o proof of concept, kdy mě zajímalo, jak moc je složité nastavit Linux + 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-premise serveru.
Slovníček
ASP.NET Core | Open-source webový framework od Microsoftu (první release 2016). |
Kestrel | Odlehčený, cross-platform webový server od Microsoftu, který je součástí ASP.NET Core projektu. |
Nginx | Původem ruský webový server, na kterém běží ~třetina webových stránek na internetu. |
IIS | Webový server od Microsoftu s podporou .NET |
VMPlayer | VMware Workstation Player je zdarma dostupná aplikace pro správu a spuštění virutálního operačního systému. |
Reverzní proxy | Proxy na straně serveru. Proxy požadavky přeposílá na další server(y). Může také sloužit pro nastavení load balancingu, kešování, zabezpečení, přidání šifrování apod. |
Bridged network | Propojí virtuální počítač se sítí pomocí 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ě VMPlayer, 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 (zvolil jsem linuxovou distribuci Ubuntu). V Linuxu pak 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átky (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 VMPlayer 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 Apachi). 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í se z klienta
Před tím, než zadáme adresu našeho webu do prohlížeče, musíme nastavit DNS záznam. Otevřeme notepad jako administrátor 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