├── global.json
├── HelloAspNetCore3.Api
├── appsettings.Development.json
├── HelloAspNetCore3.Api.csproj
├── appsettings.json
├── WeatherForecast.cs
├── .dockerignore
├── Api.Dockerfile
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Controllers
│ └── WeatherForecastController.cs
└── Startup.cs
├── Nginx
├── Nginx.Dockerfile
├── nginx-no-ssl.conf
├── localhost.conf
├── nginx.conf
├── localhost.crt
└── localhost.key
├── docker-compose.yml
├── HelloAspNetCore3.sln
├── .vscode
├── tasks.json
└── launch.json
├── ReadMe.md
└── .gitignore
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "3.0.100"
4 | }
5 | }
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/HelloAspNetCore3.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/Nginx/Nginx.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:latest
2 |
3 | COPY nginx.conf /etc/nginx/nginx.conf
4 | COPY localhost.crt /etc/ssl/certs/localhost.crt
5 | COPY localhost.key /etc/ssl/private/localhost.key
6 |
7 | # docker build -t nginx-reverseproxy -f Nginx.Dockerfile .
8 | # docker run -d -p 80:80 --name nginx-reverseproxy nginx-reverseproxy
9 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace HelloAspNetCore3.Api
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 |
3 | services:
4 |
5 | reverseproxy:
6 | build:
7 | context: ./Nginx
8 | dockerfile: Nginx.Dockerfile
9 | ports:
10 | - "80:80"
11 | - "443:443"
12 | restart: always
13 |
14 | api:
15 | depends_on:
16 | - reverseproxy
17 | build:
18 | context: ./HelloAspNetCore3.Api
19 | dockerfile: Api.Dockerfile
20 | expose:
21 | - "5000"
22 | restart: always
23 |
24 | # docker-compose build
25 | # docker-compose up -d
26 | # docker-compose down
27 |
28 | # Browse to: http://localhost/weatherforecast
29 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/Api.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine AS base
2 | WORKDIR /app
3 |
4 | FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine AS build
5 | WORKDIR /src
6 | COPY ["HelloAspNetCore3.Api.csproj", "./"]
7 | RUN dotnet restore "./HelloAspNetCore3.Api.csproj"
8 | COPY . .
9 | WORKDIR "/src/."
10 | RUN dotnet build "HelloAspNetCore3.Api.csproj" -c Release -o /app/build
11 |
12 | FROM build AS publish
13 | RUN dotnet publish "HelloAspNetCore3.Api.csproj" -c Release -o /app/publish
14 |
15 | FROM base AS final
16 | WORKDIR /app
17 | COPY --from=publish /app/publish .
18 | ENV ASPNETCORE_URLS http://*:5000
19 | ENTRYPOINT ["dotnet", "HelloAspNetCore3.Api.dll"]
20 |
21 | # docker build -t hello-aspnetcore3 -f Api.Dockerfile .
22 | # docker run -d -p 5000:5000 --name hello-aspnetcore3 hello-aspnetcore3
23 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace HelloAspNetCore3.Api
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Nginx/nginx-no-ssl.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | events { worker_connections 1024; }
4 |
5 | http {
6 |
7 | sendfile on;
8 |
9 | upstream web-api {
10 | server api:5000;
11 | }
12 |
13 | server {
14 | listen 80;
15 | server_name $hostname;
16 | location / {
17 | proxy_pass http://web-api;
18 | proxy_redirect off;
19 | proxy_http_version 1.1;
20 | proxy_cache_bypass $http_upgrade;
21 | proxy_set_header Upgrade $http_upgrade;
22 | proxy_set_header Connection keep-alive;
23 | proxy_set_header Host $host;
24 | proxy_set_header X-Real-IP $remote_addr;
25 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
26 | proxy_set_header X-Forwarded-Proto $scheme;
27 | proxy_set_header X-Forwarded-Host $server_name;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:31073",
8 | "sslPort": 44326
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "weatherforecast",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "HelloAspNetCore3.Api": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "weatherforecast",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | },
27 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/Nginx/localhost.conf:
--------------------------------------------------------------------------------
1 | [req]
2 | default_bits = 2048
3 | default_keyfile = localhost.key
4 | distinguished_name = req_distinguished_name
5 | req_extensions = req_ext
6 | x509_extensions = v3_ca
7 |
8 | [req_distinguished_name]
9 | countryName = Country Name (2 letter code)
10 | countryName_default = US
11 | stateOrProvinceName = State or Province Name (full name)
12 | stateOrProvinceName_default = Texas
13 | localityName = Locality Name (eg, city)
14 | localityName_default = Dallas
15 | organizationName = Organization Name (eg, company)
16 | organizationName_default = localhost
17 | organizationalUnitName = organizationalunit
18 | organizationalUnitName_default = Development
19 | commonName = Common Name (e.g. server FQDN or YOUR name)
20 | commonName_default = localhost
21 | commonName_max = 64
22 |
23 | [req_ext]
24 | subjectAltName = @alt_names
25 |
26 | [v3_ca]
27 | subjectAltName = @alt_names
28 |
29 | [alt_names]
30 | DNS.1 = localhost
31 | DNS.2 = 127.0.0.1
32 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloAspNetCore3.Api", "HelloAspNetCore3.Api\HelloAspNetCore3.Api.csproj", "{6BFEE9FB-B75D-4CC7-A1D4-412A93BE486D}"
5 | EndProject
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{322216D0-5DA8-4ECD-9337-F91D53C814D8}"
7 | ProjectSection(SolutionItems) = preProject
8 | global.json = global.json
9 | ReadMe.md = ReadMe.md
10 | EndProjectSection
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {6BFEE9FB-B75D-4CC7-A1D4-412A93BE486D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {6BFEE9FB-B75D-4CC7-A1D4-412A93BE486D}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {6BFEE9FB-B75D-4CC7-A1D4-412A93BE486D}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {6BFEE9FB-B75D-4CC7-A1D4-412A93BE486D}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | EndGlobal
24 |
--------------------------------------------------------------------------------
/Nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | events { worker_connections 1024; }
4 |
5 | http {
6 |
7 | sendfile on;
8 |
9 | upstream web-api {
10 | server api:5000;
11 | }
12 |
13 | server {
14 | listen 80;
15 | server_name localhost;
16 |
17 | location / {
18 | return 301 https://$host$request_uri;
19 | }
20 | }
21 |
22 | server {
23 | listen 443 ssl;
24 | server_name localhost;
25 |
26 | ssl_certificate /etc/ssl/certs/localhost.crt;
27 | ssl_certificate_key /etc/ssl/private/localhost.key;
28 |
29 | location / {
30 | proxy_pass http://web-api;
31 | proxy_redirect off;
32 | proxy_http_version 1.1;
33 | proxy_cache_bypass $http_upgrade;
34 | proxy_set_header Upgrade $http_upgrade;
35 | proxy_set_header Connection keep-alive;
36 | proxy_set_header Host $host;
37 | proxy_set_header X-Real-IP $remote_addr;
38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
39 | proxy_set_header X-Forwarded-Proto $scheme;
40 | proxy_set_header X-Forwarded-Host $server_name;
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Nginx/localhost.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDfjCCAmagAwIBAgIJAPvW08kghpisMA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNV
3 | BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGRGFsbGFzMRIwEAYDVQQK
4 | DAlsb2NhbGhvc3QxFDASBgNVBAsMC0RldmVsb3BtZW50MRIwEAYDVQQDDAlsb2Nh
5 | bGhvc3QwHhcNMTkxMDA5MjA0NTA2WhcNMjAxMDA4MjA0NTA2WjBsMQswCQYDVQQG
6 | EwJVUzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkRhbGxhczESMBAGA1UECgwJ
7 | bG9jYWxob3N0MRQwEgYDVQQLDAtEZXZlbG9wbWVudDESMBAGA1UEAwwJbG9jYWxo
8 | b3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSyfxkHf8JooHRyg
9 | w/dIoxbggta7vS1jh4aip3S9aSOJHrEMEgS+0c9DYTcLDvjwpiHeFaexrRJZnGBy
10 | 4dAuID0027gRsW0f0e7kqn09kqfpup4u2Ts3MUtx3mIqBvFNllWfXoL8QXnRTDIo
11 | zNQviRrEk7JyEgLqC+xYLdJXk2gLtcSNu2QO182LllaOZ4COMG1Lr83AYvzpoo3L
12 | a6gxB/79qdhvjRmWWXCTao6Z0Cxr+86pciOnvq6IPwm+YX5iRwaM3CZI26QhE341
13 | zFIqO6f5GfWFTtCJGDWmzUGvI5dIC1vJHfRK5w+Jteaw4WjILzRtAma1XLBUTiHg
14 | xkM3AwIDAQABoyMwITAfBgNVHREEGDAWgglsb2NhbGhvc3SCCTEyNy4wLjAuMTAN
15 | BgkqhkiG9w0BAQsFAAOCAQEAiI48kPgm4ETq0eI0IwiEe7K3pRm0ppdd6qUBsN4j
16 | uQFtwv9RdYj564I6iU0xVfCBIkrnsT5ESKo0esu99l99IC4xrJn3N5K0jjYJFNPO
17 | ydxv2Z2i3YwBzGCLuOEPbPZaSf2IBuuz9zTqNHN4TPGxcSDcCRZelwU8A1qOVg4/
18 | cIl8spRkLpIT7Dxt/i9UthbT4RMG5rDoT02OHwjFPrgE+XTZP8OnkEtqbnwPQTnd
19 | 4cDBdOLEOnEl3lRZ2Oo8p05KuB8S0fEDaWvFbtmasFZ0uSSLO4ez8wLRn10jn3Sc
20 | HRF312LTS4fdMJXofi4TvVlSscJM9ertZ4Qsa+O9tYIifw==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace HelloAspNetCore3.Api.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private static readonly string[] Summaries = new[]
15 | {
16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17 | };
18 |
19 | private readonly ILogger _logger;
20 |
21 | public WeatherForecastController(ILogger logger)
22 | {
23 | _logger = logger;
24 | }
25 |
26 | [HttpGet]
27 | public IEnumerable Get()
28 | {
29 | var rng = new Random();
30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
31 | {
32 | Date = DateTime.Now.AddDays(index),
33 | TemperatureC = rng.Next(-20, 55),
34 | Summary = Summaries[rng.Next(Summaries.Length)]
35 | })
36 | .ToArray();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/HelloAspNetCore3.Api/HelloAspNetCore3.Api.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/HelloAspNetCore3.Api/HelloAspNetCore3.Api.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "${workspaceFolder}/HelloAspNetCore3.Api/HelloAspNetCore3.Api.csproj",
36 | "/property:GenerateFullPaths=true",
37 | "/consoleloggerparameters:NoSummary"
38 | ],
39 | "problemMatcher": "$msCompile"
40 | }
41 | ]
42 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (web)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/HelloAspNetCore3.Api/bin/Debug/netcoreapp3.0/HelloAspNetCore3.Api.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}/HelloAspNetCore3.Api",
16 | "stopAtEntry": false,
17 | // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
18 | "serverReadyAction": {
19 | "action": "openExternally",
20 | "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
21 | },
22 | "env": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | },
25 | "sourceFileMap": {
26 | "/Views": "${workspaceFolder}/Views"
27 | }
28 | },
29 | {
30 | "name": ".NET Core Attach",
31 | "type": "coreclr",
32 | "request": "attach",
33 | "processId": "${command:pickProcess}"
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/Nginx/localhost.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9LJ/GQd/wmigd
3 | HKDD90ijFuCC1ru9LWOHhqKndL1pI4kesQwSBL7Rz0NhNwsO+PCmId4Vp7GtElmc
4 | YHLh0C4gPTTbuBGxbR/R7uSqfT2Sp+m6ni7ZOzcxS3HeYioG8U2WVZ9egvxBedFM
5 | MijM1C+JGsSTsnISAuoL7Fgt0leTaAu1xI27ZA7XzYuWVo5ngI4wbUuvzcBi/Omi
6 | jctrqDEH/v2p2G+NGZZZcJNqjpnQLGv7zqlyI6e+rog/Cb5hfmJHBozcJkjbpCET
7 | fjXMUio7p/kZ9YVO0IkYNabNQa8jl0gLW8kd9ErnD4m15rDhaMgvNG0CZrVcsFRO
8 | IeDGQzcDAgMBAAECggEAaqsw5H/coDSsjc3IsPdM0/lgWyZt8fwX9SFrsfTXoONS
9 | vCWk4rweRPwTyEtbRvQD7gmGyrsmKqsAMHcKEF5sw+z/Uy11fJBFswB7m87G210n
10 | I/1x+Te0pW0fJgBAJm4GC9D37jj5uInSBJ779pNmwm5/jbC/NXzDMDnydtP2Ybz/
11 | IZutO+B1ALurXEPU7CxTbS9374dWYlTD6Z0Jx0/yKnupwv0NOxnlDkiMysc9NZa5
12 | N1UqKEE74rfF3DadiE/ZT3JC9azeiwLgcXoWkU23NmR5ADQwHjadk8gGA9iMVIiq
13 | ASN31ihbznBehuxvx4b2h4jd6EU9EsNX1lfYYO+kAQKBgQDi91gc2N42bQt9O3G9
14 | L/W7dr1UJOzCzIDsMAJqHnRYluzFSHwQeVZdhr/AcQ8moDadyxtvcFUaU/X1HOmk
15 | N2iD4DBs/41p0eIeKjq0Ymbr+QelGmAZ+su39wPg5qLHb7sA06RF8nyYScPg+Bkx
16 | u5x6rRsun56VjIM69o44KA1tAQKBgQDVX61VDZmxjyaPX7UF3b0s2x0KRIOYHZrU
17 | Z/dph2/wQWy/XZ1EWYdlDBE4XuAIn1BULqIQTq3P2ixptO4rmfuy/B0kiANfpEJ6
18 | sxm+/WdzRNvv0lMl8/+GljB42pAbTiE0EkGj/rpsh64wjbua26eLfgeG5Tgeidvc
19 | 00p1FerwAwKBgQCcTpeiFkDC3spAzsV/8x2aoyW0Y1GivlAzWMTw7FRYBmi9XTQD
20 | 7GxsMLayA6rZgRDcDtqwHn6diSEkU2scqwQRfj4bcsujCuZcu9x+Ch6zeGepbsas
21 | Xaoa4cUMCAomq23wHdFOUrc38eUyc+p186zKV5kWvNrsRz7BRrefOQY2AQKBgBBi
22 | EET/jlV70FIh3xxcMjJHgKtRJ2l+nGzCrtSDeazQ2TC4V2LwHN09V/UkE7+Vu+06
23 | x2bJI79Z2R8krUTbxd+wS+yKJPgq/I+/QLLRcif/mYOIeqnnWi9TSNV+sqHmFdaR
24 | sEiPPnEm2dEQkN8LDoo/WwSYhP6TRzZlYsoqrKdRAoGAM8pagzePjgHcuBT+6M6S
25 | zxPlwXEyKJ1BVRTk5n6MOinE7OF0ga1/y+9TiUMRCXgovd6MEnC/MddLxZ1GoBy5
26 | xqb9MX0wmQTqcfMgBayHak5uyYpVcqPhmcPx4ADXqtF0wZQ5TeSxeYTwAA1IhCNA
27 | SFRLBiecxsyUfFWK8gWJ6Zk=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/HelloAspNetCore3.Api/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.HttpOverrides;
9 | using Microsoft.AspNetCore.HttpsPolicy;
10 | using Microsoft.AspNetCore.Mvc;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.DependencyInjection;
13 | using Microsoft.Extensions.Hosting;
14 | using Microsoft.Extensions.Logging;
15 |
16 | namespace HelloAspNetCore3.Api
17 | {
18 | public class Startup
19 | {
20 | public Startup(IConfiguration configuration)
21 | {
22 | Configuration = configuration;
23 | }
24 |
25 | public IConfiguration Configuration { get; }
26 |
27 | // This method gets called by the runtime. Use this method to add services to the container.
28 | public void ConfigureServices(IServiceCollection services)
29 | {
30 | services.AddControllers();
31 | }
32 |
33 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
34 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
35 | {
36 | if (env.IsDevelopment())
37 | {
38 | app.UseDeveloperExceptionPage();
39 | }
40 |
41 | app.UseForwardedHeaders(new ForwardedHeadersOptions
42 | {
43 | ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost
44 | });
45 |
46 | // app.UseHttpsRedirection();
47 |
48 | app.UseRouting();
49 |
50 | app.UseAuthorization();
51 |
52 | app.UseEndpoints(endpoints =>
53 | {
54 | endpoints.MapControllers();
55 | });
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | # ASP.NET Core 3.0 Web API with Nginx Reverse Proxy for SSL
2 |
3 | ## Prerequisites
4 |
5 | - [Docker Desktop](https://www.docker.com/products/docker-desktop)
6 | - .NET Core SDK version 3.0 or greater
7 |
8 | ## Web API Application
9 |
10 | - Create a new Web API application.
11 |
12 | ```
13 | mkdir HelloAspNetCore3 && cd HelloAspNetCore3
14 | dotnet new sln --name HelloAspNetCore3
15 | dotnet new webapi --name HelloAspNetCore3.Api
16 | dotnet sln add HelloAspNetCore3.Api/HelloAspNetCore3.Api.csproj
17 | ```
18 |
19 | - Insert the following code in the `Configure` method of `Startup`, after `app.UseDeveloperExceptionPage`.
20 |
21 | ```csharp
22 | app.UseForwardedHeaders(new ForwardedHeadersOptions
23 | {
24 | ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
25 | });
26 | ```
27 |
28 | ## Web API Container
29 |
30 | - Add **Api.Dockerfile** to the Web API project.
31 |
32 | ```docker
33 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine AS base
34 | WORKDIR /app
35 |
36 | FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine AS build
37 | WORKDIR /src
38 | COPY ["HelloAspNetCore3.Api.csproj", "./"]
39 | RUN dotnet restore "./HelloAspNetCore3.Api.csproj"
40 | COPY . .
41 | WORKDIR "/src/."
42 | RUN dotnet build "HelloAspNetCore3.Api.csproj" -c Release -o /app/build
43 |
44 | FROM build AS publish
45 | RUN dotnet publish "HelloAspNetCore3.Api.csproj" -c Release -o /app/publish
46 |
47 | FROM base AS final
48 | WORKDIR /app
49 | COPY --from=publish /app/publish .
50 | ENV ASPNETCORE_URLS http://*:5000
51 | ENTRYPOINT ["dotnet", "HelloAspNetCore3.Api.dll"]
52 | ```
53 |
54 | - Open terminal at Web API project folder, build then run the container image.
55 |
56 | ```
57 | docker build -t hello-aspnetcore3 -f Api.Dockerfile .
58 | docker run -d -p 5000:5000 --name hello-aspnetcore3 hello-aspnetcore3
59 | ```
60 |
61 | - Browse to: `http://localhost:5000/weatherforecast`
62 |
63 | > **Note**: You need to build and run individual containers only to validate the image and application. The container and image can then me removed.
64 |
65 | - Stop and remove the container and image.
66 |
67 | ```
68 | docker rm -f hello-aspnetcore3
69 | docker rmi hello-aspnetcore3
70 | ```
71 |
72 | ## Nginx Container
73 |
74 | - Add **Nginx** folder at the solution level.
75 | - Add **nginx.conf** file.
76 |
77 | ```conf
78 | worker_processes 1;
79 |
80 | events { worker_connections 1024; }
81 |
82 | http {
83 |
84 | sendfile on;
85 |
86 | upstream web-api {
87 | server api:5000;
88 | }
89 |
90 | server {
91 | listen 80;
92 | server_name $hostname;
93 | location / {
94 | proxy_pass http://web-api;
95 | proxy_redirect off;
96 | proxy_http_version 1.1;
97 | proxy_cache_bypass $http_upgrade;
98 | proxy_set_header Upgrade $http_upgrade;
99 | proxy_set_header Connection keep-alive;
100 | proxy_set_header Host $host;
101 | proxy_set_header X-Real-IP $remote_addr;
102 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
103 | proxy_set_header X-Forwarded-Proto $scheme;
104 | proxy_set_header X-Forwarded-Host $server_name;
105 | }
106 | }
107 | }
108 | ```
109 |
110 | - Add **Nginx.Dockerfile** file.
111 |
112 | ```docker
113 | FROM nginx:latest
114 |
115 | COPY nginx.conf /etc/nginx/nginx.conf
116 | ```
117 |
118 | ## Docker Compose
119 |
120 | - Add **docker-compose.yml** at the solution level.
121 |
122 | ```yml
123 | version: "3.7"
124 |
125 | services:
126 |
127 | reverseproxy:
128 | build:
129 | context: ./Nginx
130 | dockerfile: Nginx.Dockerfile
131 | ports:
132 | - "80:80"
133 | restart: always
134 |
135 | api:
136 | depends_on:
137 | - reverseproxy
138 | build:
139 | context: ./HelloAspNetCore3.Api
140 | dockerfile: Api.Dockerfile
141 | expose:
142 | - "5000"
143 | restart: always
144 | ```
145 |
146 | > **Note**: Specifying `depends_on` for the `api` service places it in the same bridge network as `reverseproxy`, so that nginx can forward requests to it via `proxy_pass`. For this to work, the `api` service name must match the upstream server specified in the `nginx.conf` file. While `reverseproxy` is exposed to the host via `ports`, `api` is only exposed to `reverseproxy`.
147 |
148 | - Build **api** and **reverseproxy** images.
149 |
150 | ```
151 | docker-compose build
152 | ```
153 |
154 | - Run the containers via `docker-compose`.
155 |
156 | ```
157 | docker-compose up -d
158 | ```
159 |
160 | - Browse to `http://localhost/weatherforecast`
161 | - Stop the containers.
162 |
163 | ```
164 | docker-compose down
165 | ```
166 |
167 | ## SSL Setup
168 |
169 | - Add **localhost.conf** to **Nginx** folder.
170 |
171 | ```conf
172 | [req]
173 | default_bits = 2048
174 | default_keyfile = localhost.key
175 | distinguished_name = req_distinguished_name
176 | req_extensions = req_ext
177 | x509_extensions = v3_ca
178 |
179 | [req_distinguished_name]
180 | countryName = Country Name (2 letter code)
181 | countryName_default = US
182 | stateOrProvinceName = State or Province Name (full name)
183 | stateOrProvinceName_default = Texas
184 | localityName = Locality Name (eg, city)
185 | localityName_default = Dallas
186 | organizationName = Organization Name (eg, company)
187 | organizationName_default = localhost
188 | organizationalUnitName = organizationalunit
189 | organizationalUnitName_default = Development
190 | commonName = Common Name (e.g. server FQDN or YOUR name)
191 | commonName_default = localhost
192 | commonName_max = 64
193 |
194 | [req_ext]
195 | subjectAltName = @alt_names
196 |
197 | [v3_ca]
198 | subjectAltName = @alt_names
199 |
200 | [alt_names]
201 | DNS.1 = localhost
202 | DNS.2 = 127.0.0.1
203 | ```
204 |
205 | - Open terminal at **Nginx** folder to create certificate using OpenSSL.
206 | - Enter `Strong@Passw0rd` when prompted for export password.
207 |
208 | ```
209 | sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf -passin pass:Strong@Passw0rd
210 | sudo openssl pkcs12 -export -out localhost.pfx -inkey localhost.key -in localhost.crt
211 | ```
212 |
213 | - Add the certificate to the trusted CA root store.
214 | - Open the KeyChain Access app (spotlight on MacOS).
215 | - Select System in the Keychains pane, and drag your .pfx certificate into the certificate list pane.
216 | - Double-click your certificate, and under the trust section select Always Trust.
217 | - Update **Nginx.Dockerfile** to copy public and private key files.
218 |
219 | ```docker
220 | COPY localhost.crt /etc/ssl/certs/localhost.crt
221 | COPY localhost.key /etc/ssl/private/localhost.key
222 | ```
223 |
224 | - Update **nginx.conf** to load certificate key pair.
225 |
226 | ```conf
227 | worker_processes 1;
228 |
229 | events { worker_connections 1024; }
230 |
231 | http {
232 |
233 | sendfile on;
234 |
235 | upstream web-api {
236 | server api:5000;
237 | }
238 |
239 | server {
240 | listen 80;
241 | server_name localhost;
242 |
243 | location / {
244 | return 301 https://$host$request_uri;
245 | }
246 | }
247 |
248 | server {
249 | listen 443 ssl;
250 | server_name localhost;
251 |
252 | ssl_certificate /etc/ssl/certs/localhost.crt;
253 | ssl_certificate_key /etc/ssl/private/localhost.key;
254 |
255 | location / {
256 | proxy_pass http://web-api;
257 | proxy_redirect off;
258 | proxy_http_version 1.1;
259 | proxy_cache_bypass $http_upgrade;
260 | proxy_set_header Upgrade $http_upgrade;
261 | proxy_set_header Connection keep-alive;
262 | proxy_set_header Host $host;
263 | proxy_set_header X-Real-IP $remote_addr;
264 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
265 | proxy_set_header X-Forwarded-Proto $scheme;
266 | proxy_set_header X-Forwarded-Host $server_name;
267 | }
268 | }
269 | }
270 | ```
271 |
272 | - Edit **docker-compose.yml** to map `reverseproxy` to port 443.
273 |
274 | ```docker
275 | ports:
276 | - "80:80"
277 | - "443:443"
278 | ```
279 |
280 | - Build images and run containers.
281 |
282 | ```
283 | docker-compose build
284 | docker-compose up -d
285 | ```
286 |
287 | - Browse to: http://localhost/weatherforecast
288 | - Stop containers.
289 |
290 | ```
291 | docker-compose down
292 | ```
293 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # globs
2 | Makefile.in
3 | *.userprefs
4 | *.usertasks
5 | config.make
6 | config.status
7 | aclocal.m4
8 | install-sh
9 | autom4te.cache/
10 | *.tar.gz
11 | tarballs/
12 | test-results/
13 |
14 | # Mac bundle stuff
15 | *.dmg
16 | *.app
17 |
18 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
19 | # General
20 | .DS_Store
21 | .AppleDouble
22 | .LSOverride
23 |
24 | # Icon must end with two \r
25 | Icon
26 |
27 |
28 | # Thumbnails
29 | ._*
30 |
31 | # Files that might appear in the root of a volume
32 | .DocumentRevisions-V100
33 | .fseventsd
34 | .Spotlight-V100
35 | .TemporaryItems
36 | .Trashes
37 | .VolumeIcon.icns
38 | .com.apple.timemachine.donotpresent
39 |
40 | # Directories potentially created on remote AFP share
41 | .AppleDB
42 | .AppleDesktop
43 | Network Trash Folder
44 | Temporary Items
45 | .apdisk
46 |
47 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
48 | # Windows thumbnail cache files
49 | Thumbs.db
50 | ehthumbs.db
51 | ehthumbs_vista.db
52 |
53 | # Dump file
54 | *.stackdump
55 |
56 | # Folder config file
57 | [Dd]esktop.ini
58 |
59 | # Recycle Bin used on file shares
60 | $RECYCLE.BIN/
61 |
62 | # Windows Installer files
63 | *.cab
64 | *.msi
65 | *.msix
66 | *.msm
67 | *.msp
68 |
69 | # Windows shortcuts
70 | *.lnk
71 |
72 | # content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
73 | ## Ignore Visual Studio temporary files, build results, and
74 | ## files generated by popular Visual Studio add-ons.
75 | ##
76 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
77 |
78 | # User-specific files
79 | *.suo
80 | *.user
81 | *.userosscache
82 | *.sln.docstates
83 |
84 | # User-specific files (MonoDevelop/Xamarin Studio)
85 | *.userprefs
86 |
87 | # Build results
88 | [Dd]ebug/
89 | [Dd]ebugPublic/
90 | [Rr]elease/
91 | [Rr]eleases/
92 | x64/
93 | x86/
94 | bld/
95 | [Bb]in/
96 | [Oo]bj/
97 | [Ll]og/
98 |
99 | # Visual Studio 2015/2017 cache/options directory
100 | .vs/
101 | # Uncomment if you have tasks that create the project's static files in wwwroot
102 | #wwwroot/
103 |
104 | # Visual Studio 2017 auto generated files
105 | Generated\ Files/
106 |
107 | # MSTest test Results
108 | [Tt]est[Rr]esult*/
109 | [Bb]uild[Ll]og.*
110 |
111 | # NUNIT
112 | *.VisualState.xml
113 | TestResult.xml
114 |
115 | # Build Results of an ATL Project
116 | [Dd]ebugPS/
117 | [Rr]eleasePS/
118 | dlldata.c
119 |
120 | # Benchmark Results
121 | BenchmarkDotNet.Artifacts/
122 |
123 | # .NET Core
124 | project.lock.json
125 | project.fragment.lock.json
126 | artifacts/
127 |
128 | # StyleCop
129 | StyleCopReport.xml
130 |
131 | # Files built by Visual Studio
132 | *_i.c
133 | *_p.c
134 | *_h.h
135 | *.ilk
136 | *.meta
137 | *.obj
138 | *.iobj
139 | *.pch
140 | *.pdb
141 | *.ipdb
142 | *.pgc
143 | *.pgd
144 | *.rsp
145 | *.sbr
146 | *.tlb
147 | *.tli
148 | *.tlh
149 | *.tmp
150 | *.tmp_proj
151 | *_wpftmp.csproj
152 | *.log
153 | *.vspscc
154 | *.vssscc
155 | .builds
156 | *.pidb
157 | *.svclog
158 | *.scc
159 |
160 | # Chutzpah Test files
161 | _Chutzpah*
162 |
163 | # Visual C++ cache files
164 | ipch/
165 | *.aps
166 | *.ncb
167 | *.opendb
168 | *.opensdf
169 | *.sdf
170 | *.cachefile
171 | *.VC.db
172 | *.VC.VC.opendb
173 |
174 | # Visual Studio profiler
175 | *.psess
176 | *.vsp
177 | *.vspx
178 | *.sap
179 |
180 | # Visual Studio Trace Files
181 | *.e2e
182 |
183 | # TFS 2012 Local Workspace
184 | $tf/
185 |
186 | # Guidance Automation Toolkit
187 | *.gpState
188 |
189 | # ReSharper is a .NET coding add-in
190 | _ReSharper*/
191 | *.[Rr]e[Ss]harper
192 | *.DotSettings.user
193 |
194 | # JustCode is a .NET coding add-in
195 | .JustCode
196 |
197 | # TeamCity is a build add-in
198 | _TeamCity*
199 |
200 | # DotCover is a Code Coverage Tool
201 | *.dotCover
202 |
203 | # AxoCover is a Code Coverage Tool
204 | .axoCover/*
205 | !.axoCover/settings.json
206 |
207 | # Visual Studio code coverage results
208 | *.coverage
209 | *.coveragexml
210 |
211 | # NCrunch
212 | _NCrunch_*
213 | .*crunch*.local.xml
214 | nCrunchTemp_*
215 |
216 | # MightyMoose
217 | *.mm.*
218 | AutoTest.Net/
219 |
220 | # Web workbench (sass)
221 | .sass-cache/
222 |
223 | # Installshield output folder
224 | [Ee]xpress/
225 |
226 | # DocProject is a documentation generator add-in
227 | DocProject/buildhelp/
228 | DocProject/Help/*.HxT
229 | DocProject/Help/*.HxC
230 | DocProject/Help/*.hhc
231 | DocProject/Help/*.hhk
232 | DocProject/Help/*.hhp
233 | DocProject/Help/Html2
234 | DocProject/Help/html
235 |
236 | # Click-Once directory
237 | publish/
238 |
239 | # Publish Web Output
240 | *.[Pp]ublish.xml
241 | *.azurePubxml
242 | # Note: Comment the next line if you want to checkin your web deploy settings,
243 | # but database connection strings (with potential passwords) will be unencrypted
244 | *.pubxml
245 | *.publishproj
246 |
247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
248 | # checkin your Azure Web App publish settings, but sensitive information contained
249 | # in these scripts will be unencrypted
250 | PublishScripts/
251 |
252 | # NuGet Packages
253 | *.nupkg
254 | # The packages folder can be ignored because of Package Restore
255 | **/[Pp]ackages/*
256 | # except build/, which is used as an MSBuild target.
257 | !**/[Pp]ackages/build/
258 | # Uncomment if necessary however generally it will be regenerated when needed
259 | #!**/[Pp]ackages/repositories.config
260 | # NuGet v3's project.json files produces more ignorable files
261 | *.nuget.props
262 | *.nuget.targets
263 |
264 | # Microsoft Azure Build Output
265 | csx/
266 | *.build.csdef
267 |
268 | # Microsoft Azure Emulator
269 | ecf/
270 | rcf/
271 |
272 | # Windows Store app package directories and files
273 | AppPackages/
274 | BundleArtifacts/
275 | Package.StoreAssociation.xml
276 | _pkginfo.txt
277 | *.appx
278 |
279 | # Visual Studio cache files
280 | # files ending in .cache can be ignored
281 | *.[Cc]ache
282 | # but keep track of directories ending in .cache
283 | !*.[Cc]ache/
284 |
285 | # Others
286 | ClientBin/
287 | ~$*
288 | *~
289 | *.dbmdl
290 | *.dbproj.schemaview
291 | *.jfm
292 | *.pfx
293 | *.publishsettings
294 | orleans.codegen.cs
295 |
296 | # Including strong name files can present a security risk
297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
298 | #*.snk
299 |
300 | # Since there are multiple workflows, uncomment next line to ignore bower_components
301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
302 | #bower_components/
303 |
304 | # RIA/Silverlight projects
305 | Generated_Code/
306 |
307 | # Backup & report files from converting an old project file
308 | # to a newer Visual Studio version. Backup files are not needed,
309 | # because we have git ;-)
310 | _UpgradeReport_Files/
311 | Backup*/
312 | UpgradeLog*.XML
313 | UpgradeLog*.htm
314 | ServiceFabricBackup/
315 | *.rptproj.bak
316 |
317 | # SQL Server files
318 | *.mdf
319 | *.ldf
320 | *.ndf
321 |
322 | # Business Intelligence projects
323 | *.rdl.data
324 | *.bim.layout
325 | *.bim_*.settings
326 | *.rptproj.rsuser
327 |
328 | # Microsoft Fakes
329 | FakesAssemblies/
330 |
331 | # GhostDoc plugin setting file
332 | *.GhostDoc.xml
333 |
334 | # Node.js Tools for Visual Studio
335 | .ntvs_analysis.dat
336 | node_modules/
337 |
338 | # Visual Studio 6 build log
339 | *.plg
340 |
341 | # Visual Studio 6 workspace options file
342 | *.opt
343 |
344 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
345 | *.vbw
346 |
347 | # Visual Studio LightSwitch build output
348 | **/*.HTMLClient/GeneratedArtifacts
349 | **/*.DesktopClient/GeneratedArtifacts
350 | **/*.DesktopClient/ModelManifest.xml
351 | **/*.Server/GeneratedArtifacts
352 | **/*.Server/ModelManifest.xml
353 | _Pvt_Extensions
354 |
355 | # Paket dependency manager
356 | .paket/paket.exe
357 | paket-files/
358 |
359 | # FAKE - F# Make
360 | .fake/
361 |
362 | # JetBrains Rider
363 | .idea/
364 | *.sln.iml
365 |
366 | # CodeRush personal settings
367 | .cr/personal
368 |
369 | # Python Tools for Visual Studio (PTVS)
370 | __pycache__/
371 | *.pyc
372 |
373 | # Cake - Uncomment if you are using it
374 | # tools/**
375 | # !tools/packages.config
376 |
377 | # Tabs Studio
378 | *.tss
379 |
380 | # Telerik's JustMock configuration file
381 | *.jmconfig
382 |
383 | # BizTalk build output
384 | *.btp.cs
385 | *.btm.cs
386 | *.odx.cs
387 | *.xsd.cs
388 |
389 | # OpenCover UI analysis results
390 | OpenCover/
391 |
392 | # Azure Stream Analytics local run output
393 | ASALocalRun/
394 |
395 | # MSBuild Binary and Structured Log
396 | *.binlog
397 |
398 | # NVidia Nsight GPU debugger configuration file
399 | *.nvuser
400 |
401 | # MFractors (Xamarin productivity tool) working folder
402 | .mfractor/
403 |
404 | # Local History for Visual Studio
405 | .localhistory/
--------------------------------------------------------------------------------