[{"data":1,"prerenderedAt":3223},["ShallowReactive",2],{"nav-products":3,"article-\u002Farticles\u002Fhow_to\u002F2026-08-14-how-to-host-a-legacy-aspnet-framework-application-on-aws-fargate\u002F":10,"article-latest-\u002Farticles\u002Fhow_to\u002F2026-08-14-how-to-host-a-legacy-aspnet-framework-application-on-aws-fargate\u002F":1759},[4],{"name":5,"tagline":6,"to":7,"isInternal":8,"icon":9},"Valdras Gate","Self-hosted OpenVPN® server on AWS — no licenses to manage","\u002Fproducts\u002Fgate\u002F",true,"\u002Fpublic\u002Fimg\u002Fproducts\u002Fgate\u002Fgate_logo.png",{"id":11,"title":12,"author":13,"body":14,"category":1745,"cover":1746,"date":1747,"description":1748,"extension":1749,"featured":1750,"isFeatured":1751,"meta":1752,"navigation":8,"path":1753,"preview":1754,"seo":1755,"stem":1756,"updated":1757,"__hash__":1758},"articles\u002Farticles\u002Fhow_to\u002F2026-08-14-how-to-host-a-legacy-aspnet-framework-application-on-aws-fargate.md","How to Host a Legacy ASP.NET Framework Application on AWS Fargate","David Gatti",{"type":15,"value":16,"toc":1697},"minimark",[17,30,37,44,49,54,57,60,63,66,70,73,80,84,87,93,187,201,204,207,211,222,225,278,285,292,296,299,303,306,309,376,380,383,389,396,400,407,410,414,421,431,435,439,442,449,456,460,463,466,469,472,476,479,510,515,519,526,531,596,602,606,613,616,627,630,638,645,652,655,664,668,671,688,691,704,707,710,714,717,720,723,727,731,734,737,754,757,761,764,767,773,777,782,852,855,859,862,892,895,910,914,917,926,929,938,941,947,950,956,960,966,992,995,1001,1004,1007,1011,1014,1031,1034,1037,1040,1057,1060,1063,1067,1070,1077,1079,1104,1107,1113,1116,1122,1125,1128,1209,1212,1215,1218,1222,1225,1228,1234,1237,1243,1253,1256,1260,1267,1277,1280,1288,1292,1299,1537,1540,1547,1550,1561,1564,1567,1573,1576,1582,1588,1591,1595,1598,1601,1604,1607,1610,1613,1617,1621,1624,1628,1631,1635,1638,1642,1645,1649,1655,1659,1668,1672,1679,1683,1686,1690,1693],[18,19,20,21,25,26,29],"p",{},"If you need to ",[22,23,24],"strong",{},"host a legacy"," ASP.NET ",[22,27,28],{},"Framework application on AWS",", you don't necessarily need to rewrite it or move your infrastructure to Azure.",[18,31,32,33,36],{},"AWS Fargate can run ASP.NET ",[22,34,35],{},"Framework applications in Windows containers"," using Amazon ECS, allowing you to run existing IIS applications on AWS without managing Windows servers yourself.",[18,38,39,40,43],{},"In this guide, I'll show you how to containerize a legacy ASP.NET Framework application, deploy it to ",[22,41,42],{},"Amazon ECS with AWS Fargate",", handle ASP.NET session state, configure load balancer health checks, and understand the costs and limitations of running Windows containers on Fargate.",[45,46,48],"h2",{"id":47},"downsides","Downsides",[50,51,53],"h3",{"id":52},"windows-container-image-size","Windows container image size",[18,55,56],{},"The main downside of running ASP.NET on Fargate is the size of Windows container images.",[18,58,59],{},"For traditional ASP.NET applications running on the .NET Framework, Microsoft recommends using Windows Server Core as the base image. Windows container images are considerably larger than the Linux images you may be used to working with. For reference, the Windows Server 2022 Server Core image was around 2.76 GB uncompressed when Windows Server 2022 was released.",[18,61,62],{},"The final image will be larger once you add ASP.NET, the .NET Framework, your application, and any other dependencies. There is no fixed image size, so the actual size depends on the Windows version, Microsoft image, and your application.",[18,64,65],{},"This becomes important when deploying or autoscaling the application. When Fargate starts a new Windows task, it needs to download the container image before the container can start. Large images therefore mean longer startup times, which is something you need to account for when configuring autoscaling.",[50,67,69],{"id":68},"minimum-windows-fargate-task-size","Minimum Windows Fargate task size",[18,71,72],{},"The second downside is the minimum amount of compute you can allocate.",[18,74,75,76,79],{},"Windows containers on Fargate require at least ",[22,77,78],{},"1 vCPU and 2 GB of memory",". With Linux containers, Fargate can go as low as 0.25 vCPU and 512 MB of memory. This means that even a very small ASP.NET application has a higher minimum running cost simply because it is running on Windows.",[50,81,83],{"id":82},"windows-fargate-pricing","Windows Fargate pricing",[18,85,86],{},"Windows containers are also considerably more expensive to run on Fargate than Linux containers.",[18,88,89,90,92],{},"The smallest Windows Fargate task you can run has ",[22,91,78],{},". Using the current AWS pricing for US East (N. Virginia), one task costs approximately:",[94,95,96,110],"table",{},[97,98,99],"thead",{},[100,101,102,105,108],"tr",{},[103,104],"th",{},[103,106],{"align":107},"right",[103,109],{"align":107},[111,112,113,122,133,144,155,170],"tbody",{},[100,114,115,118,120],{},[116,117],"td",{},[116,119],{"align":107},[116,121],{"align":107},[100,123,124,127,130],{},[116,125,126],{},"Charge",[116,128,129],{"align":107},"Per hour",[116,131,132],{"align":107},"30 days, 24\u002F7",[100,134,135,138,141],{},[116,136,137],{},"1 vCPU",[116,139,140],{"align":107},"$0.0915",[116,142,143],{"align":107},"$65.88",[100,145,146,149,152],{},[116,147,148],{},"2 GB memory",[116,150,151],{"align":107},"$0.0200",[116,153,154],{"align":107},"$14.40",[100,156,157,160,165],{},[116,158,159],{},"Windows OS charge",[116,161,162],{"align":107},[22,163,164],{},"$0.0460",[116,166,167],{"align":107},[22,168,169],{},"$33.12",[100,171,172,177,182],{},[116,173,174],{},[22,175,176],{},"Total",[116,178,179],{"align":107},[22,180,181],{},"$0.1575",[116,183,184],{"align":107},[22,185,186],{},"$113.40",[18,188,189,190,192,193,196,197,200],{},"The important part here is the ",[22,191,159],{},". AWS adds approximately ",[22,194,195],{},"$0.046 per vCPU per hour"," specifically for running Windows. With the minimum 1 vCPU task running continuously, that is about ",[22,198,199],{},"$33.12 per month just for the Windows operating system charge",".",[18,202,203],{},"This is billed by AWS as a Windows OS charge. You are not paying Microsoft directly or buying a separate Windows license yourself; the Windows licensing cost is included as part of the Fargate billing.",[18,205,206],{},"It is also important to understand that the Windows OS charge is not the only reason Windows costs more. AWS also charges more for the Windows vCPU and memory compared with Linux.",[50,208,210],{"id":209},"windows-vs-linux-cost","Windows vs Linux cost",[18,212,213,214,217,218,221],{},"For comparison, an equivalent Linux Fargate task with 1 vCPU and 2 GB of memory costs approximately ",[22,215,216],{},"$0.0494 per hour",", or about ",[22,219,220],{},"$35.55 per month"," running continuously.",[18,223,224],{},"So the comparison looks like this:",[94,226,227,235],{},[97,228,229],{},[100,230,231,233],{},[103,232],{},[103,234],{"align":107},[111,236,237,243,251,259,266],{},[100,238,239,241],{},[116,240],{},[116,242],{"align":107},[100,244,245,248],{},[116,246,247],{},"Task",[116,249,250],{"align":107},"Approx. monthly cost",[100,252,253,256],{},[116,254,255],{},"Linux — 1 vCPU \u002F 2 GB",[116,257,258],{"align":107},"$35.55",[100,260,261,264],{},[116,262,263],{},"Windows — 1 vCPU \u002F 2 GB",[116,265,186],{"align":107},[100,267,268,273],{},[116,269,270],{},[22,271,272],{},"Difference",[116,274,275],{"align":107},[22,276,277],{},"$77.85",[18,279,280,281,284],{},"Of that $77.85 difference, approximately ",[22,282,283],{},"$33.12 is the explicit Windows OS charge",". The remaining difference comes from the higher Windows Fargate CPU and memory rates.",[18,286,287,288,291],{},"In other words, the same 1 vCPU and 2 GB task costs roughly ",[22,289,290],{},"3.2 times more on Windows than on Linux"," before adding things such as load balancers, data transfer, CloudWatch, public IPv4 addresses, or other AWS services.",[50,293,295],{"id":294},"supported-windows-versions","Supported Windows versions",[18,297,298],{},"AWS currently supports Windows Server 2019 and Windows Server 2022 containers on Fargate, in both Full and Core variants.",[50,300,302],{"id":301},"unsupported-features-on-windows-fargate","Unsupported features on Windows Fargate",[18,304,305],{},"There are also several AWS features available to Linux containers on Fargate that are not currently supported when running Windows containers.",[18,307,308],{},"According to the AWS documentation, Windows containers on Fargate do not support:",[310,311,312,318,323,328,333,338,343,348,353,358,366,371],"ul",{},[313,314,315],"li",{},[22,316,317],{},"Amazon FSx",[313,319,320],{},[22,321,322],{},"Amazon EFS volumes",[313,324,325],{},[22,326,327],{},"Amazon EBS volumes",[313,329,330],{},[22,331,332],{},"Fargate Spot",[313,334,335],{},[22,336,337],{},"ENI trunking",[313,339,340],{},[22,341,342],{},"gMSA (group Managed Service Accounts) for Windows containers",[313,344,345],{},[22,346,347],{},"AWS App Mesh service and proxy integration",[313,349,350],{},[22,351,352],{},"FireLens log router integration",[313,354,355],{},[22,356,357],{},"Image volumes",[313,359,360,361,365],{},"The ",[362,363,364],"code",{},"environmentFiles"," task definition parameter",[313,367,360,368,365],{},[362,369,370],{},"maxSwap",[313,372,360,373,365],{},[362,374,375],{},"swappiness",[50,377,379],{"id":378},"other-windows-fargate-limitations","Other Windows Fargate limitations",[18,381,382],{},"There are a few additional differences worth knowing about.",[18,384,360,385,388],{},[362,386,387],{},"VOLUME"," option inside a Dockerfile is ignored for Windows containers on Fargate. If your application needs local storage, AWS recommends using bind mounts defined in the ECS task definition instead.",[18,390,391,392,395],{},"Windows Fargate also does not support the ",[362,393,394],{},"ulimits"," task definition parameter, which Linux Fargate supports.",[50,397,399],{"id":398},"seekable-oci-support","Seekable OCI support",[18,401,402,403,406],{},"Another important limitation is ",[22,404,405],{},"Seekable OCI (SOCI)",". On Linux, Fargate can use SOCI to start a container before the entire image has been downloaded. This is particularly useful with large container images. Windows containers on Fargate do not support SOCI, so the complete Windows container image needs to be downloaded before the container can start.",[18,408,409],{},"This matters for ASP.NET applications because Windows container images are already relatively large. Without SOCI lazy loading, the size of the image has a direct impact on how quickly a new task can start during a deployment or autoscaling event.",[50,411,413],{"id":412},"architecture-and-task-size-limitations","Architecture and task size limitations",[18,415,416,417,420],{},"Windows Fargate tasks are also limited to the ",[22,418,419],{},"x86-64 architecture",". Linux Fargate can run on both x86-64 and ARM64.",[18,422,423,424,426,427,430],{},"Finally, Windows Fargate supports a smaller range of task sizes. Windows starts at ",[22,425,78],{}," and currently goes up to ",[22,428,429],{},"4 vCPU and 30 GB of memory",". Linux Fargate additionally supports 0.25 and 0.5 vCPU configurations at the low end and 8, 16, and 32 vCPU configurations at the high end.",[45,432,434],{"id":433},"making-aspnet-stateless","Making ASP.NET stateless",[50,436,438],{"id":437},"how-aspnet-sessions-work-by-default","How ASP.NET sessions work by default",[18,440,441],{},"Other than these differences, there is nothing stopping you from running and scaling an ASP.NET application on Fargate. The main thing you need to pay attention to is how the application handles user sessions.",[18,443,444,445,448],{},"By default, classic ASP.NET Framework stores session data using ",[362,446,447],{},"InProc"," mode. This means the actual session data is stored in the RAM of the IIS worker process running your application.",[18,450,451,452,455],{},"The browser only stores a cookie containing the session ID, such as ",[362,453,454],{},"ASP.NET_SessionId",". The actual data associated with that session remains in the memory of the server.",[50,457,459],{"id":458},"why-inproc-becomes-a-problem-with-fargate","Why InProc becomes a problem with Fargate",[18,461,462],{},"This works perfectly well when you have one server, but it becomes a problem when you start running multiple Fargate tasks behind a load balancer.",[18,464,465],{},"For example, a user's first request might go to Task A, where their session is created and stored in memory. Their next request might go to Task B. The browser will still send the same session ID, but Task B does not have the corresponding session data because it exists only in the memory of Task A.",[18,467,468],{},"The same problem occurs if Task A crashes, is replaced during a deployment, or is terminated by autoscaling. Everything stored in its memory disappears with it.",[18,470,471],{},"Fortunately, ASP.NET Framework already has a solution for this, and in many cases you do not need to rewrite your application's session handling.",[50,473,475],{"id":474},"aspnet-session-state-options","ASP.NET session-state options",[18,477,478],{},"ASP.NET supports several session-state modes:",[310,480,481,486,492,498,504],{},[313,482,483,485],{},[362,484,447],{}," — stores session data in the memory of the IIS process. This is the default.",[313,487,488,491],{},[362,489,490],{},"StateServer"," — stores session data in a separate ASP.NET State Service.",[313,493,494,497],{},[362,495,496],{},"SQLServer"," — stores session data in SQL Server.",[313,499,500,503],{},[362,501,502],{},"Custom"," — allows you to use your own session-state provider.",[313,505,506,509],{},[362,507,508],{},"Off"," — disables ASP.NET session state completely.",[18,511,512,513,200],{},"For a Fargate deployment, the important part is moving the session state outside of ",[362,514,447],{},[50,516,518],{"id":517},"store-aspnet-sessions-in-sql-server","Store ASP.NET sessions in SQL Server",[18,520,521,522,525],{},"For example, you can configure ASP.NET to store sessions in SQL Server directly from ",[362,523,524],{},"Web.config",":",[527,528,530],"h4",{"id":529},"configure-webconfig","Configure Web.config",[532,533,538],"pre",{"className":534,"code":535,"language":536,"meta":537,"style":537},"language-xml shiki shiki-themes github-light github-dark","\u003Cconfiguration>\n  \u003Csystem.web>\n    \u003CsessionState\n      mode=\"SQLServer\"\n      sqlConnectionString=\"data source=YOUR_SQL_SERVER;user id=USERNAME;password=PASSWORD\"\n      cookieless=\"false\"\n      timeout=\"20\" \u002F>\n  \u003C\u002Fsystem.web>\n\u003C\u002Fconfiguration>\n","xml","",[362,539,540,548,554,560,566,572,578,584,590],{"__ignoreMap":537},[541,542,545],"span",{"class":543,"line":544},"line",1,[541,546,547],{},"\u003Cconfiguration>\n",[541,549,551],{"class":543,"line":550},2,[541,552,553],{},"  \u003Csystem.web>\n",[541,555,557],{"class":543,"line":556},3,[541,558,559],{},"    \u003CsessionState\n",[541,561,563],{"class":543,"line":562},4,[541,564,565],{},"      mode=\"SQLServer\"\n",[541,567,569],{"class":543,"line":568},5,[541,570,571],{},"      sqlConnectionString=\"data source=YOUR_SQL_SERVER;user id=USERNAME;password=PASSWORD\"\n",[541,573,575],{"class":543,"line":574},6,[541,576,577],{},"      cookieless=\"false\"\n",[541,579,581],{"class":543,"line":580},7,[541,582,583],{},"      timeout=\"20\" \u002F>\n",[541,585,587],{"class":543,"line":586},8,[541,588,589],{},"  \u003C\u002Fsystem.web>\n",[541,591,593],{"class":543,"line":592},9,[541,594,595],{},"\u003C\u002Fconfiguration>\n",[18,597,360,598,601],{},[362,599,600],{},"mode=\"SQLServer\""," setting tells ASP.NET to stop keeping session state inside the IIS process and use SQL Server instead.",[50,603,605],{"id":604},"prepare-sql-server-for-session-state","Prepare SQL Server for session state",[18,607,608,609,612],{},"Before this works, the SQL Server needs the ASP.NET session-state database and stored procedures. Microsoft provides the ",[362,610,611],{},"aspnet_regsql.exe"," utility for doing this.",[18,614,615],{},"For example:",[532,617,621],{"className":618,"code":619,"language":620,"meta":537,"style":537},"language-powershell shiki shiki-themes github-light github-dark","aspnet_regsql.exe -S YOUR_SQL_SERVER -E -ssadd -sstype p\n","powershell",[362,622,623],{"__ignoreMap":537},[541,624,625],{"class":543,"line":544},[541,626,619],{},[18,628,629],{},"The important option here is:",[532,631,636],{"className":632,"code":634,"language":635,"meta":537},[633],"language-text","-sstype p\n","text",[362,637,634],{"__ignoreMap":537},[18,639,640,641,644],{},"This tells ASP.NET to store the session data persistently inside the ",[362,642,643],{},"ASPState"," database.",[18,646,647,648,651],{},"Without this option, the default configuration stores the session data in SQL Server's ",[362,649,650],{},"tempdb",". That still allows multiple Fargate tasks to share sessions, but the session data will disappear if SQL Server itself is restarted.",[18,653,654],{},"If SQL authentication is being used instead of Windows authentication, the same setup can be performed using a username and password:",[532,656,658],{"className":618,"code":657,"language":620,"meta":537,"style":537},"aspnet_regsql.exe -S YOUR_SQL_SERVER -U USERNAME -P PASSWORD -ssadd -sstype p\n",[362,659,660],{"__ignoreMap":537},[541,661,662],{"class":543,"line":544},[541,663,657],{},[50,665,667],{"id":666},"existing-application-code-does-not-need-to-change","Existing application code does not need to change",[18,669,670],{},"Once this is configured, existing application code such as:",[532,672,676],{"className":673,"code":674,"language":675,"meta":537,"style":537},"language-csharp shiki shiki-themes github-light github-dark","Session[\"UserId\"] = 123;\nSession[\"Cart\"] = cart;\n","csharp",[362,677,678,683],{"__ignoreMap":537},[541,679,680],{"class":543,"line":544},[541,681,682],{},"Session[\"UserId\"] = 123;\n",[541,684,685],{"class":543,"line":550},[541,686,687],{},"Session[\"Cart\"] = cart;\n",[18,689,690],{},"normally does not need to change. ASP.NET handles storing and retrieving the session from SQL Server instead of keeping it in local memory.",[18,692,693,694,697,698,700,701,703],{},"One thing to be aware of is that objects placed inside ",[362,695,696],{},"Session"," must be serializable when using ",[362,699,496],{}," mode. With ",[362,702,447],{},", ASP.NET can keep arbitrary objects directly in memory, but once session state is moved outside the IIS process, ASP.NET needs to serialize those objects before storing them.",[18,705,706],{},"Once the session data is stored in a shared location, it no longer matters which Fargate task receives the next request. Every task can access the same session data.",[18,708,709],{},"This means ECS can start additional tasks when traffic increases, terminate tasks when traffic decreases, replace unhealthy tasks, or deploy a new version of the application without destroying the user's session.",[50,711,713],{"id":712},"sticky-sessions-vs-shared-session-state","Sticky sessions vs shared session state",[18,715,716],{},"Another option is to enable sticky sessions on the Application Load Balancer, which attempts to keep the same user connected to the same Fargate task. While this can work, it does not make the application truly stateless. If that particular task disappears, its in-memory session disappears with it.",[18,718,719],{},"Moving session state outside the container is therefore the better approach when you want to take full advantage of Fargate and ECS autoscaling.",[18,721,722],{},"Once your application no longer depends on data stored inside a specific task, you can run multiple copies behind an Application Load Balancer and scale them up and down like any other containerized application on AWS.",[45,724,726],{"id":725},"building-the-aspnet-docker-image","Building the ASP.NET Docker image",[50,728,730],{"id":729},"what-the-microsoft-base-image-includes","What the Microsoft base image includes",[18,732,733],{},"Putting an ASP.NET Framework application inside a container is simpler than it might initially seem.",[18,735,736],{},"Microsoft already provides an official ASP.NET Framework container image that includes:",[310,738,739,742,745,748,751],{},[313,740,741],{},"Windows Server Core",[313,743,744],{},"IIS 10",[313,746,747],{},".NET Framework",[313,749,750],{},"ASP.NET support for IIS",[313,752,753],{},"The service required to keep IIS running inside the container",[18,755,756],{},"This means that you do not need to install Windows, IIS, or ASP.NET yourself.",[50,758,760],{"id":759},"create-a-minimal-aspnet-application","Create a minimal ASP.NET application",[18,762,763],{},"For a very basic example, we can create a container that runs a single ASP.NET page.",[18,765,766],{},"Create a directory containing these two files:",[532,768,771],{"className":769,"code":770,"language":635,"meta":537},[633],"Dockerfile\nDefault.aspx\n",[362,772,770],{"__ignoreMap":537},[527,774,776],{"id":775},"defaultaspx","Default.aspx",[18,778,360,779,781],{},[362,780,776],{}," file can be as simple as:",[532,783,787],{"className":784,"code":785,"language":786,"meta":537,"style":537},"language-aspx shiki shiki-themes github-light github-dark","\u003C%@ Page Language=\"C#\" %>\n\n\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Ctitle>ASP.NET on AWS\u003C\u002Ftitle>\n\u003C\u002Fhead>\n\u003Cbody>\n    \u003Ch1>Hello World from ASP.NET\u003C\u002Fh1>\n    \u003Cp>Server time: \u003C%= DateTime.UtcNow %>\u003C\u002Fp>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","aspx",[362,788,789,794,799,804,809,814,819,824,829,834,840,846],{"__ignoreMap":537},[541,790,791],{"class":543,"line":544},[541,792,793],{},"\u003C%@ Page Language=\"C#\" %>\n",[541,795,796],{"class":543,"line":550},[541,797,798],{"emptyLinePlaceholder":8},"\n",[541,800,801],{"class":543,"line":556},[541,802,803],{},"\u003C!DOCTYPE html>\n",[541,805,806],{"class":543,"line":562},[541,807,808],{},"\u003Chtml>\n",[541,810,811],{"class":543,"line":568},[541,812,813],{},"\u003Chead>\n",[541,815,816],{"class":543,"line":574},[541,817,818],{},"    \u003Ctitle>ASP.NET on AWS\u003C\u002Ftitle>\n",[541,820,821],{"class":543,"line":580},[541,822,823],{},"\u003C\u002Fhead>\n",[541,825,826],{"class":543,"line":586},[541,827,828],{},"\u003Cbody>\n",[541,830,831],{"class":543,"line":592},[541,832,833],{},"    \u003Ch1>Hello World from ASP.NET\u003C\u002Fh1>\n",[541,835,837],{"class":543,"line":836},10,[541,838,839],{},"    \u003Cp>Server time: \u003C%= DateTime.UtcNow %>\u003C\u002Fp>\n",[541,841,843],{"class":543,"line":842},11,[541,844,845],{},"\u003C\u002Fbody>\n",[541,847,849],{"class":543,"line":848},12,[541,850,851],{},"\u003C\u002Fhtml>\n",[18,853,854],{},"Using the server time is useful here because it confirms that the page is actually being processed by ASP.NET rather than simply being served by IIS as a static HTML file.",[50,856,858],{"id":857},"create-the-dockerfile","Create the Dockerfile",[18,860,861],{},"The Dockerfile itself can then be:",[532,863,867],{"className":864,"code":865,"language":866,"meta":537,"style":537},"language-dockerfile shiki shiki-themes github-light github-dark","FROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Faspnet:4.8.1-windowsservercore-ltsc2022\n\nWORKDIR C:inetpubwwwroot\n\nCOPY Default.aspx .\n","dockerfile",[362,868,869,874,878,883,887],{"__ignoreMap":537},[541,870,871],{"class":543,"line":544},[541,872,873],{},"FROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Faspnet:4.8.1-windowsservercore-ltsc2022\n",[541,875,876],{"class":543,"line":550},[541,877,798],{"emptyLinePlaceholder":8},[541,879,880],{"class":543,"line":556},[541,881,882],{},"WORKDIR C:inetpubwwwroot\n",[541,884,885],{"class":543,"line":562},[541,886,798],{"emptyLinePlaceholder":8},[541,888,889],{"class":543,"line":568},[541,890,891],{},"COPY Default.aspx .\n",[18,893,894],{},"And that is essentially all you need.",[18,896,897,898,901,902,905,906,909],{},"Microsoft's ASP.NET base image already exposes port ",[362,899,900],{},"80"," and starts the IIS ",[362,903,904],{},"w3svc"," service when the container starts, so you do not need to create your own ",[362,907,908],{},"ENTRYPOINT"," or install IIS manually.",[50,911,913],{"id":912},"build-and-run-the-container-locally","Build and run the container locally",[18,915,916],{},"You can build the image with:",[532,918,920],{"className":618,"code":919,"language":620,"meta":537,"style":537},"docker build -t aspnet-hello-world .\n",[362,921,922],{"__ignoreMap":537},[541,923,924],{"class":543,"line":544},[541,925,919],{},[18,927,928],{},"And run it locally with:",[532,930,932],{"className":618,"code":931,"language":620,"meta":537,"style":537},"docker run --rm -p 8080:80 aspnet-hello-world\n",[362,933,934],{"__ignoreMap":537},[541,935,936],{"class":543,"line":544},[541,937,931],{},[18,939,940],{},"You can then open:",[532,942,945],{"className":943,"code":944,"language":635,"meta":537},[633],"http:\u002F\u002Flocalhost:8080\n",[362,946,944],{"__ignoreMap":537},[18,948,949],{},"and you should see:",[532,951,954],{"className":952,"code":953,"language":635,"meta":537},[633],"Hello World from ASP.NET\nServer time: ...\n",[362,955,953],{"__ignoreMap":537},[50,957,959],{"id":958},"containerizing-a-real-aspnet-application","Containerizing a real ASP.NET application",[18,961,962,963,965],{},"For a real application, instead of copying ",[362,964,776],{},", you would copy the published application into the same IIS directory:",[532,967,969],{"className":864,"code":968,"language":866,"meta":537,"style":537},"FROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Faspnet:4.8.1-windowsservercore-ltsc2022\n\nWORKDIR C:inetpubwwwroot\n\nCOPY .\u002Fpublish\u002F .\n",[362,970,971,975,979,983,987],{"__ignoreMap":537},[541,972,973],{"class":543,"line":544},[541,974,873],{},[541,976,977],{"class":543,"line":550},[541,978,798],{"emptyLinePlaceholder":8},[541,980,981],{"class":543,"line":556},[541,982,882],{},[541,984,985],{"class":543,"line":562},[541,986,798],{"emptyLinePlaceholder":8},[541,988,989],{"class":543,"line":568},[541,990,991],{},"COPY .\u002Fpublish\u002F .\n",[18,993,994],{},"The important part is that the application ultimately ends up inside:",[532,996,999],{"className":997,"code":998,"language":635,"meta":537},[633],"C:inetpubwwwroot\n",[362,1000,998],{"__ignoreMap":537},[18,1002,1003],{},"From there, IIS inside the Microsoft container image handles the application in much the same way as IIS running on a normal Windows Server.",[18,1005,1006],{},"Once the image works locally, the same image can be pushed to Amazon ECR and used by an ECS Fargate task.",[45,1008,1010],{"id":1009},"precompiling-aspnet-before-deployment","Precompiling ASP.NET before deployment",[18,1012,1013],{},"Another thing worth considering with older ASP.NET applications is what happens when the application starts for the first time.",[18,1015,1016,1017,1020,1021,1020,1024,1020,1027,1030],{},"Classic ASP.NET can compile parts of the application dynamically when they are first requested. Depending on how the project was built, this can include ",[362,1018,1019],{},".aspx",", ",[362,1022,1023],{},".ascx",[362,1025,1026],{},"App_Code",[362,1028,1029],{},"Global.asax",", and other application resources.",[18,1032,1033],{},"On a traditional Windows server this might not be very noticeable because the server stays online for a long time. The compilation happens once, the result is cached, and future requests are fast.",[18,1035,1036],{},"With Fargate, things are slightly different.",[18,1038,1039],{},"Every time ECS starts a new task, you are starting a fresh Windows container with a fresh IIS instance. This can happen during:",[310,1041,1042,1045,1048,1051,1054],{},[313,1043,1044],{},"A new deployment",[313,1046,1047],{},"Autoscaling",[313,1049,1050],{},"Task replacement",[313,1052,1053],{},"An application crash",[313,1055,1056],{},"Infrastructure maintenance",[18,1058,1059],{},"If the application relies on runtime compilation, every new task may need to perform some of that work again before it can serve requests at full speed.",[18,1061,1062],{},"This means the first requests reaching a newly started task can be slower than normal.",[50,1064,1066],{"id":1065},"compile-the-application-during-the-build","Compile the application during the build",[18,1068,1069],{},"A better approach is to precompile as much of the ASP.NET application as possible before creating the final container image.",[18,1071,1072,1073,1076],{},"Microsoft provides ",[362,1074,1075],{},"aspnet_compiler.exe"," specifically for this purpose.",[18,1078,615],{},[532,1080,1082],{"className":618,"code":1081,"language":620,"meta":537,"style":537},"C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_compiler.exe ^\n  -p C:src ^\n  -v \u002F ^\n  C:publish\n",[362,1083,1084,1089,1094,1099],{"__ignoreMap":537},[541,1085,1086],{"class":543,"line":544},[541,1087,1088],{},"C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_compiler.exe ^\n",[541,1090,1091],{"class":543,"line":550},[541,1092,1093],{},"  -p C:src ^\n",[541,1095,1096],{"class":543,"line":556},[541,1097,1098],{},"  -v \u002F ^\n",[541,1100,1101],{"class":543,"line":562},[541,1102,1103],{},"  C:publish\n",[18,1105,1106],{},"This takes the ASP.NET application from:",[532,1108,1111],{"className":1109,"code":1110,"language":635,"meta":537},[633],"C:src\n",[362,1112,1110],{"__ignoreMap":537},[18,1114,1115],{},"and produces a precompiled version inside:",[532,1117,1120],{"className":1118,"code":1119,"language":635,"meta":537},[633],"C:publish\n",[362,1121,1119],{"__ignoreMap":537},[18,1123,1124],{},"The resulting files can then be copied into the final ASP.NET container image.",[18,1126,1127],{},"A multi-stage Dockerfile could look like this:",[532,1129,1131],{"className":864,"code":1130,"language":866,"meta":537,"style":537},"FROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Fsdk:4.8.1-windowsservercore-ltsc2022 AS build\n\nWORKDIR C:src\n\nCOPY . .\n\nRUN C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_compiler.exe ^\n    -p C:src ^\n    -v \u002F ^\n    C:publish\n\nFROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Faspnet:4.8.1-windowsservercore-ltsc2022\n\nWORKDIR C:inetpubwwwroot\n\nCOPY --from=build C:publish .\n",[362,1132,1133,1138,1142,1147,1151,1156,1160,1165,1170,1175,1180,1184,1188,1193,1198,1203],{"__ignoreMap":537},[541,1134,1135],{"class":543,"line":544},[541,1136,1137],{},"FROM mcr.microsoft.com\u002Fdotnet\u002Fframework\u002Fsdk:4.8.1-windowsservercore-ltsc2022 AS build\n",[541,1139,1140],{"class":543,"line":550},[541,1141,798],{"emptyLinePlaceholder":8},[541,1143,1144],{"class":543,"line":556},[541,1145,1146],{},"WORKDIR C:src\n",[541,1148,1149],{"class":543,"line":562},[541,1150,798],{"emptyLinePlaceholder":8},[541,1152,1153],{"class":543,"line":568},[541,1154,1155],{},"COPY . .\n",[541,1157,1158],{"class":543,"line":574},[541,1159,798],{"emptyLinePlaceholder":8},[541,1161,1162],{"class":543,"line":580},[541,1163,1164],{},"RUN C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_compiler.exe ^\n",[541,1166,1167],{"class":543,"line":586},[541,1168,1169],{},"    -p C:src ^\n",[541,1171,1172],{"class":543,"line":592},[541,1173,1174],{},"    -v \u002F ^\n",[541,1176,1177],{"class":543,"line":836},[541,1178,1179],{},"    C:publish\n",[541,1181,1182],{"class":543,"line":842},[541,1183,798],{"emptyLinePlaceholder":8},[541,1185,1186],{"class":543,"line":848},[541,1187,873],{},[541,1189,1191],{"class":543,"line":1190},13,[541,1192,798],{"emptyLinePlaceholder":8},[541,1194,1196],{"class":543,"line":1195},14,[541,1197,882],{},[541,1199,1201],{"class":543,"line":1200},15,[541,1202,798],{"emptyLinePlaceholder":8},[541,1204,1206],{"class":543,"line":1205},16,[541,1207,1208],{},"COPY --from=build C:publish .\n",[18,1210,1211],{},"The first stage contains the development and build tools necessary to compile the application.",[18,1213,1214],{},"The second stage uses the normal ASP.NET runtime image and contains only the files required to actually run the application.",[18,1216,1217],{},"This also keeps the build tools out of the production container.",[45,1219,1221],{"id":1220},"health-checks-for-the-load-balancer","Health checks for the load balancer",[18,1223,1224],{},"When running ASP.NET on Fargate behind an Application Load Balancer, the load balancer needs a way to determine whether each Fargate task is actually ready to receive traffic.",[18,1226,1227],{},"The target group does this by periodically sending an HTTP request to a configured path, for example:",[532,1229,1232],{"className":1230,"code":1231,"language":635,"meta":537},[633],"\u002Fhealth\n",[362,1233,1231],{"__ignoreMap":537},[18,1235,1236],{},"or, for a classic ASP.NET Framework application:",[532,1238,1241],{"className":1239,"code":1240,"language":635,"meta":537},[633],"\u002Fhealth.aspx\n",[362,1242,1240],{"__ignoreMap":537},[18,1244,1245,1246,1249,1250,200],{},"The endpoint should return ",[362,1247,1248],{},"200 OK"," when the application is healthy and ready to receive traffic. If the application is not ready or a critical dependency is unavailable, it should return an error such as ",[362,1251,1252],{},"503 Service Unavailable",[18,1254,1255],{},"This prevents the load balancer from sending users to a container that has started but whose application is not yet ready.",[50,1257,1259],{"id":1258},"which-aspnet-versions-have-built-in-health-checks","Which ASP.NET versions have built-in health checks?",[18,1261,1262,1263,1266],{},"If your application uses ASP.NET ",[22,1264,1265],{},"Core 2.2 or newer",", Microsoft provides a built-in Health Checks feature designed specifically for scenarios such as load balancers and container orchestrators.",[18,1268,1269,1270,25,1273,1276],{},"If you are running ",[22,1271,1272],{},"classic",[22,1274,1275],{},"Framework",", including .NET Framework 4.x applications, this built-in HTTP Health Checks feature is not available.",[18,1278,1279],{},"For classic ASP.NET Framework applications, you therefore need to create the health-check endpoint yourself.",[18,1281,1282,1283,25,1285,1287],{},"The example below is specifically for ",[22,1284,1272],{},[22,1286,1275],{}," applications.",[50,1289,1291],{"id":1290},"creating-a-simple-aspnet-framework-health-endpoint","Creating a simple ASP.NET Framework health endpoint",[18,1293,1294,1295,1298],{},"A very basic ",[362,1296,1297],{},"health.aspx"," could look like this:",[532,1300,1302],{"className":784,"code":1301,"language":786,"meta":537,"style":537},"\u003C%@ Page Language=\"C#\" EnableSessionState=\"false\" %>\n\u003C%@ Import Namespace=\"System\" %>\n\u003C%@ Import Namespace=\"System.Configuration\" %>\n\u003C%@ Import Namespace=\"System.Data.SqlClient\" %>\n\n\u003Cscript runat=\"server\">\n\nprotected void Page_Load(object sender, EventArgs e)\n{\n    Response.ContentType = \"text\u002Fplain\";\n    Response.TrySkipIisCustomErrors = true;\n\n    try\n    {\n        string connectionString =\n            ConfigurationManager\n                .ConnectionStrings[\"AppDatabase\"]\n                .ConnectionString;\n\n        using (SqlConnection connection =\n            new SqlConnection(connectionString))\n        {\n            connection.Open();\n\n            using (SqlCommand command =\n                new SqlCommand(\"SELECT 1\", connection))\n            {\n                command.CommandTimeout = 2;\n                command.ExecuteScalar();\n            }\n        }\n\n        Response.StatusCode = 200;\n        Response.Write(\"OK\");\n    }\n    catch\n    {\n        Response.StatusCode = 503;\n        Response.Write(\"UNHEALTHY\");\n    }\n}\n\n\u003C\u002Fscript>\n",[362,1303,1304,1309,1314,1319,1324,1328,1333,1337,1342,1347,1352,1357,1361,1366,1371,1376,1381,1387,1393,1398,1404,1410,1416,1422,1427,1433,1439,1445,1451,1457,1463,1469,1474,1480,1486,1492,1498,1503,1509,1515,1520,1526,1531],{"__ignoreMap":537},[541,1305,1306],{"class":543,"line":544},[541,1307,1308],{},"\u003C%@ Page Language=\"C#\" EnableSessionState=\"false\" %>\n",[541,1310,1311],{"class":543,"line":550},[541,1312,1313],{},"\u003C%@ Import Namespace=\"System\" %>\n",[541,1315,1316],{"class":543,"line":556},[541,1317,1318],{},"\u003C%@ Import Namespace=\"System.Configuration\" %>\n",[541,1320,1321],{"class":543,"line":562},[541,1322,1323],{},"\u003C%@ Import Namespace=\"System.Data.SqlClient\" %>\n",[541,1325,1326],{"class":543,"line":568},[541,1327,798],{"emptyLinePlaceholder":8},[541,1329,1330],{"class":543,"line":574},[541,1331,1332],{},"\u003Cscript runat=\"server\">\n",[541,1334,1335],{"class":543,"line":580},[541,1336,798],{"emptyLinePlaceholder":8},[541,1338,1339],{"class":543,"line":586},[541,1340,1341],{},"protected void Page_Load(object sender, EventArgs e)\n",[541,1343,1344],{"class":543,"line":592},[541,1345,1346],{},"{\n",[541,1348,1349],{"class":543,"line":836},[541,1350,1351],{},"    Response.ContentType = \"text\u002Fplain\";\n",[541,1353,1354],{"class":543,"line":842},[541,1355,1356],{},"    Response.TrySkipIisCustomErrors = true;\n",[541,1358,1359],{"class":543,"line":848},[541,1360,798],{"emptyLinePlaceholder":8},[541,1362,1363],{"class":543,"line":1190},[541,1364,1365],{},"    try\n",[541,1367,1368],{"class":543,"line":1195},[541,1369,1370],{},"    {\n",[541,1372,1373],{"class":543,"line":1200},[541,1374,1375],{},"        string connectionString =\n",[541,1377,1378],{"class":543,"line":1205},[541,1379,1380],{},"            ConfigurationManager\n",[541,1382,1384],{"class":543,"line":1383},17,[541,1385,1386],{},"                .ConnectionStrings[\"AppDatabase\"]\n",[541,1388,1390],{"class":543,"line":1389},18,[541,1391,1392],{},"                .ConnectionString;\n",[541,1394,1396],{"class":543,"line":1395},19,[541,1397,798],{"emptyLinePlaceholder":8},[541,1399,1401],{"class":543,"line":1400},20,[541,1402,1403],{},"        using (SqlConnection connection =\n",[541,1405,1407],{"class":543,"line":1406},21,[541,1408,1409],{},"            new SqlConnection(connectionString))\n",[541,1411,1413],{"class":543,"line":1412},22,[541,1414,1415],{},"        {\n",[541,1417,1419],{"class":543,"line":1418},23,[541,1420,1421],{},"            connection.Open();\n",[541,1423,1425],{"class":543,"line":1424},24,[541,1426,798],{"emptyLinePlaceholder":8},[541,1428,1430],{"class":543,"line":1429},25,[541,1431,1432],{},"            using (SqlCommand command =\n",[541,1434,1436],{"class":543,"line":1435},26,[541,1437,1438],{},"                new SqlCommand(\"SELECT 1\", connection))\n",[541,1440,1442],{"class":543,"line":1441},27,[541,1443,1444],{},"            {\n",[541,1446,1448],{"class":543,"line":1447},28,[541,1449,1450],{},"                command.CommandTimeout = 2;\n",[541,1452,1454],{"class":543,"line":1453},29,[541,1455,1456],{},"                command.ExecuteScalar();\n",[541,1458,1460],{"class":543,"line":1459},30,[541,1461,1462],{},"            }\n",[541,1464,1466],{"class":543,"line":1465},31,[541,1467,1468],{},"        }\n",[541,1470,1472],{"class":543,"line":1471},32,[541,1473,798],{"emptyLinePlaceholder":8},[541,1475,1477],{"class":543,"line":1476},33,[541,1478,1479],{},"        Response.StatusCode = 200;\n",[541,1481,1483],{"class":543,"line":1482},34,[541,1484,1485],{},"        Response.Write(\"OK\");\n",[541,1487,1489],{"class":543,"line":1488},35,[541,1490,1491],{},"    }\n",[541,1493,1495],{"class":543,"line":1494},36,[541,1496,1497],{},"    catch\n",[541,1499,1501],{"class":543,"line":1500},37,[541,1502,1370],{},[541,1504,1506],{"class":543,"line":1505},38,[541,1507,1508],{},"        Response.StatusCode = 503;\n",[541,1510,1512],{"class":543,"line":1511},39,[541,1513,1514],{},"        Response.Write(\"UNHEALTHY\");\n",[541,1516,1518],{"class":543,"line":1517},40,[541,1519,1491],{},[541,1521,1523],{"class":543,"line":1522},41,[541,1524,1525],{},"}\n",[541,1527,1529],{"class":543,"line":1528},42,[541,1530,798],{"emptyLinePlaceholder":8},[541,1532,1534],{"class":543,"line":1533},43,[541,1535,1536],{},"\u003C\u002Fscript>\n",[18,1538,1539],{},"In this example, the endpoint does two useful things.",[18,1541,1542,1543,1546],{},"First, simply reaching ",[362,1544,1545],{},"Page_Load"," proves that IIS and ASP.NET Framework are capable of processing the request.",[18,1548,1549],{},"Second, it opens a connection to SQL Server and executes:",[532,1551,1555],{"className":1552,"code":1553,"language":1554,"meta":537,"style":537},"language-sql shiki shiki-themes github-light github-dark","SELECT 1\n","sql",[362,1556,1557],{"__ignoreMap":537},[541,1558,1559],{"class":543,"line":544},[541,1560,1553],{},[18,1562,1563],{},"This is deliberately a very small query. We do not care about application data here; we only want to know whether the application can establish a connection to the database and successfully execute a query.",[18,1565,1566],{},"If everything works, the endpoint returns:",[532,1568,1571],{"className":1569,"code":1570,"language":635,"meta":537},[633],"200 OK\n",[362,1572,1570],{"__ignoreMap":537},[18,1574,1575],{},"If the database connection or query fails, it returns:",[532,1577,1580],{"className":1578,"code":1579,"language":635,"meta":537},[633],"503 Service Unavailable\n",[362,1581,1579],{"__ignoreMap":537},[18,1583,360,1584,1587],{},[362,1585,1586],{},"EnableSessionState=\"false\""," setting is also intentional. The health-check request itself does not need to create an ASP.NET user session.",[18,1589,1590],{},"If your application depends on SQL Server session state, you can explicitly test that SQL Server as another dependency rather than allowing the health-check request itself to create a session.",[45,1592,1594],{"id":1593},"final-thoughts","Final thoughts",[18,1596,1597],{},"Running ASP.NET on AWS is absolutely possible, and Fargate gives you a relatively simple way to do it without having to manage Windows servers yourself.",[18,1599,1600],{},"The biggest differences compared with running Linux containers are the larger Windows images, higher cost, slower startup times, and the reduced set of Fargate features available to Windows workloads.",[18,1602,1603],{},"The other important part is making sure your application can run across multiple containers. Older ASP.NET applications commonly store session data in the memory of the IIS process, which works fine on one server but becomes a problem once you start autoscaling.",[18,1605,1606],{},"Fortunately, ASP.NET already provides ways to move session state outside the application, such as storing it in SQL Server. In many cases, this means you can make an existing application work properly with Fargate without having to rewrite the application from scratch.",[18,1608,1609],{},"Once the application is containerized and no longer depends on the state of a particular server, the rest becomes standard AWS infrastructure: push the image to ECR, run it with ECS and Fargate, place the tasks behind an Application Load Balancer, configure the target group health check, and scale the service based on demand.",[18,1611,1612],{},"Azure may be the obvious place to look when you have an ASP.NET application, but it is certainly not the only option. If the rest of your infrastructure is already on AWS, there is very little reason to move everything somewhere else just because one application happens to be written in ASP.NET.",[45,1614,1616],{"id":1615},"frequently-asked-questions","Frequently Asked Questions",[50,1618,1620],{"id":1619},"can-you-host-a-legacy-aspnet-framework-application-on-aws","Can you host a legacy ASP.NET Framework application on AWS?",[18,1622,1623],{},"Yes. A legacy ASP.NET Framework application can run on AWS without being rewritten from scratch. One option is to package the application as a Windows container, store the image in Amazon ECR, and run it with Amazon ECS on AWS Fargate.",[50,1625,1627],{"id":1626},"can-aws-fargate-run-aspnet-framework-applications","Can AWS Fargate run ASP.NET Framework applications?",[18,1629,1630],{},"Yes. AWS Fargate can run ASP.NET Framework applications inside Windows containers. Fargate runs the Windows container while ECS handles orchestration, allowing you to deploy and scale the application without maintaining the underlying Windows servers yourself.",[50,1632,1634],{"id":1633},"can-you-run-iis-on-aws-fargate","Can you run IIS on AWS Fargate?",[18,1636,1637],{},"Yes. IIS can run inside a Windows container on AWS Fargate. Microsoft provides ASP.NET Framework container images that already include Windows Server Core, IIS, and ASP.NET, so you do not need to install and configure IIS manually inside your container.",[50,1639,1641],{"id":1640},"does-aws-fargate-support-net-framework-48","Does AWS Fargate support .NET Framework 4.8?",[18,1643,1644],{},"Yes, provided the application can run inside a compatible Windows container. Microsoft provides an official ASP.NET Framework 4.8 container image containing Windows Server Core, IIS, and ASP.NET. AWS Fargate currently supports Windows Server 2019 and Windows Server 2022 containers.",[50,1646,1648],{"id":1647},"do-i-need-to-rewrite-my-aspnet-application-before-moving-it-to-aws","Do I need to rewrite my ASP.NET application before moving it to AWS?",[18,1650,1651,1652,1654],{},"Not necessarily. Many existing ASP.NET Framework applications can be containerized with relatively few changes. The main issue is usually application state. If the application stores user sessions in IIS memory using ",[362,1653,447],{},", the session state should be moved to a shared store before running multiple Fargate tasks.",[50,1656,1658],{"id":1657},"how-should-aspnet-session-state-work-with-aws-fargate","How should ASP.NET session state work with AWS Fargate?",[18,1660,1661,1662,1664,1665,1667],{},"ASP.NET session state should normally be stored outside the container when running multiple Fargate tasks. For example, ASP.NET Framework can use ",[362,1663,496],{}," session mode instead of the default ",[362,1666,447],{}," mode. This allows different containers to access the same session data when ECS scales or replaces tasks.",[50,1669,1671],{"id":1670},"how-much-does-it-cost-to-run-aspnet-on-aws-fargate","How much does it cost to run ASP.NET on AWS Fargate?",[18,1673,1674,1675,1678],{},"Windows Fargate is considerably more expensive than an equivalent Linux task. Using the US East (N. Virginia) pricing in this guide, a continuously running Windows task with 1 vCPU and 2 GB of memory costs about ",[22,1676,1677],{},"$113.40 per 30 days",", before load balancers, networking, logging, and other AWS services.",[50,1680,1682],{"id":1681},"what-are-the-main-limitations-of-running-aspnet-on-windows-fargate","What are the main limitations of running ASP.NET on Windows Fargate?",[18,1684,1685],{},"The main limitations are larger Windows container images, higher compute costs, slower container startup times, and fewer supported Fargate features. Windows Fargate also does not currently support features including Fargate Spot, Amazon EFS, Amazon EBS, Amazon FSx, or ARM64 workloads.",[50,1687,1689],{"id":1688},"is-aws-fargate-a-good-choice-for-legacy-aspnet-applications","Is AWS Fargate a good choice for legacy ASP.NET applications?",[18,1691,1692],{},"It can be. Fargate is particularly useful when you want to keep an existing ASP.NET Framework application on AWS without managing Windows servers. The trade-offs are the higher cost of Windows containers, larger images, slower startup times, and the need to make application state work correctly across multiple containers.",[1694,1695,1696],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":537,"searchDepth":550,"depth":550,"links":1698},[1699,1710,1719,1726,1729,1733,1734],{"id":47,"depth":550,"text":48,"children":1700},[1701,1702,1703,1704,1705,1706,1707,1708,1709],{"id":52,"depth":556,"text":53},{"id":68,"depth":556,"text":69},{"id":82,"depth":556,"text":83},{"id":209,"depth":556,"text":210},{"id":294,"depth":556,"text":295},{"id":301,"depth":556,"text":302},{"id":378,"depth":556,"text":379},{"id":398,"depth":556,"text":399},{"id":412,"depth":556,"text":413},{"id":433,"depth":550,"text":434,"children":1711},[1712,1713,1714,1715,1716,1717,1718],{"id":437,"depth":556,"text":438},{"id":458,"depth":556,"text":459},{"id":474,"depth":556,"text":475},{"id":517,"depth":556,"text":518},{"id":604,"depth":556,"text":605},{"id":666,"depth":556,"text":667},{"id":712,"depth":556,"text":713},{"id":725,"depth":550,"text":726,"children":1720},[1721,1722,1723,1724,1725],{"id":729,"depth":556,"text":730},{"id":759,"depth":556,"text":760},{"id":857,"depth":556,"text":858},{"id":912,"depth":556,"text":913},{"id":958,"depth":556,"text":959},{"id":1009,"depth":550,"text":1010,"children":1727},[1728],{"id":1065,"depth":556,"text":1066},{"id":1220,"depth":550,"text":1221,"children":1730},[1731,1732],{"id":1258,"depth":556,"text":1259},{"id":1290,"depth":556,"text":1291},{"id":1593,"depth":550,"text":1594},{"id":1615,"depth":550,"text":1616,"children":1735},[1736,1737,1738,1739,1740,1741,1742,1743,1744],{"id":1619,"depth":556,"text":1620},{"id":1626,"depth":556,"text":1627},{"id":1633,"depth":556,"text":1634},{"id":1640,"depth":556,"text":1641},{"id":1647,"depth":556,"text":1648},{"id":1657,"depth":556,"text":1658},{"id":1670,"depth":556,"text":1671},{"id":1681,"depth":556,"text":1682},{"id":1688,"depth":556,"text":1689},"how_to","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-host-a-legacy-aspnet-framework-application-on-aws-fargate\u002Fcover.jpg","2026-08-14","Learn how to run legacy ASP.NET Framework apps on AWS Fargate using Windows containers, ECS, SQL Server session state, health checks, and more.","md","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-host-a-legacy-aspnet-framework-application-on-aws-fargate\u002Ffeatured.jpg",false,{},"\u002Farticles\u002Fhow_to\u002F2026-08-14-how-to-host-a-legacy-aspnet-framework-application-on-aws-fargate","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-host-a-legacy-aspnet-framework-application-on-aws-fargate\u002Fpreview.jpg",{"title":12,"description":1748},"articles\u002Fhow_to\u002F2026-08-14-how-to-host-a-legacy-aspnet-framework-application-on-aws-fargate",null,"SBJX_WUBt6duC-IZxBU0BnqIe4essc0kuNyNQXcPHNQ",[1760,2974,3085],{"id":11,"title":12,"author":13,"body":1761,"category":1745,"cover":1746,"date":1747,"description":1748,"extension":1749,"featured":1750,"isFeatured":1751,"meta":2972,"navigation":8,"path":1753,"preview":1754,"seo":2973,"stem":1756,"updated":1757,"__hash__":1758},{"type":15,"value":1762,"toc":2924},[1763,1769,1773,1777,1779,1781,1783,1785,1787,1789,1791,1793,1797,1799,1801,1805,1877,1885,1887,1889,1891,1897,1899,1945,1949,1953,1955,1957,1959,1961,1963,2013,2015,2017,2021,2025,2027,2031,2033,2035,2039,2045,2047,2049,2051,2055,2059,2061,2063,2065,2067,2069,2071,2073,2095,2099,2101,2105,2107,2147,2151,2153,2157,2159,2167,2169,2174,2178,2182,2184,2192,2194,2196,2208,2210,2218,2220,2222,2224,2226,2228,2230,2232,2234,2236,2238,2250,2252,2254,2256,2258,2263,2265,2269,2321,2323,2325,2327,2351,2353,2361,2363,2365,2373,2375,2383,2385,2390,2392,2397,2399,2403,2427,2429,2434,2436,2438,2440,2442,2452,2454,2456,2458,2470,2472,2474,2476,2478,2482,2484,2504,2506,2511,2513,2518,2520,2522,2590,2592,2594,2596,2598,2600,2602,2607,2609,2614,2620,2622,2624,2628,2634,2636,2642,2644,2648,2824,2826,2830,2832,2840,2842,2844,2849,2851,2856,2860,2862,2864,2866,2868,2870,2872,2874,2876,2878,2880,2882,2884,2886,2888,2890,2892,2894,2896,2900,2902,2908,2910,2914,2916,2918,2920,2922],[18,1764,20,1765,25,1767,29],{},[22,1766,24],{},[22,1768,28],{},[18,1770,32,1771,36],{},[22,1772,35],{},[18,1774,39,1775,43],{},[22,1776,42],{},[45,1778,48],{"id":47},[50,1780,53],{"id":52},[18,1782,56],{},[18,1784,59],{},[18,1786,62],{},[18,1788,65],{},[50,1790,69],{"id":68},[18,1792,72],{},[18,1794,75,1795,79],{},[22,1796,78],{},[50,1798,83],{"id":82},[18,1800,86],{},[18,1802,89,1803,92],{},[22,1804,78],{},[94,1806,1807,1817],{},[97,1808,1809],{},[100,1810,1811,1813,1815],{},[103,1812],{},[103,1814],{"align":107},[103,1816],{"align":107},[111,1818,1819,1827,1835,1843,1851,1863],{},[100,1820,1821,1823,1825],{},[116,1822],{},[116,1824],{"align":107},[116,1826],{"align":107},[100,1828,1829,1831,1833],{},[116,1830,126],{},[116,1832,129],{"align":107},[116,1834,132],{"align":107},[100,1836,1837,1839,1841],{},[116,1838,137],{},[116,1840,140],{"align":107},[116,1842,143],{"align":107},[100,1844,1845,1847,1849],{},[116,1846,148],{},[116,1848,151],{"align":107},[116,1850,154],{"align":107},[100,1852,1853,1855,1859],{},[116,1854,159],{},[116,1856,1857],{"align":107},[22,1858,164],{},[116,1860,1861],{"align":107},[22,1862,169],{},[100,1864,1865,1869,1873],{},[116,1866,1867],{},[22,1868,176],{},[116,1870,1871],{"align":107},[22,1872,181],{},[116,1874,1875],{"align":107},[22,1876,186],{},[18,1878,189,1879,192,1881,196,1883,200],{},[22,1880,159],{},[22,1882,195],{},[22,1884,199],{},[18,1886,203],{},[18,1888,206],{},[50,1890,210],{"id":209},[18,1892,213,1893,217,1895,221],{},[22,1894,216],{},[22,1896,220],{},[18,1898,224],{},[94,1900,1901,1909],{},[97,1902,1903],{},[100,1904,1905,1907],{},[103,1906],{},[103,1908],{"align":107},[111,1910,1911,1917,1923,1929,1935],{},[100,1912,1913,1915],{},[116,1914],{},[116,1916],{"align":107},[100,1918,1919,1921],{},[116,1920,247],{},[116,1922,250],{"align":107},[100,1924,1925,1927],{},[116,1926,255],{},[116,1928,258],{"align":107},[100,1930,1931,1933],{},[116,1932,263],{},[116,1934,186],{"align":107},[100,1936,1937,1941],{},[116,1938,1939],{},[22,1940,272],{},[116,1942,1943],{"align":107},[22,1944,277],{},[18,1946,280,1947,284],{},[22,1948,283],{},[18,1950,287,1951,291],{},[22,1952,290],{},[50,1954,295],{"id":294},[18,1956,298],{},[50,1958,302],{"id":301},[18,1960,305],{},[18,1962,308],{},[310,1964,1965,1969,1973,1977,1981,1985,1989,1993,1997,2001,2005,2009],{},[313,1966,1967],{},[22,1968,317],{},[313,1970,1971],{},[22,1972,322],{},[313,1974,1975],{},[22,1976,327],{},[313,1978,1979],{},[22,1980,332],{},[313,1982,1983],{},[22,1984,337],{},[313,1986,1987],{},[22,1988,342],{},[313,1990,1991],{},[22,1992,347],{},[313,1994,1995],{},[22,1996,352],{},[313,1998,1999],{},[22,2000,357],{},[313,2002,360,2003,365],{},[362,2004,364],{},[313,2006,360,2007,365],{},[362,2008,370],{},[313,2010,360,2011,365],{},[362,2012,375],{},[50,2014,379],{"id":378},[18,2016,382],{},[18,2018,360,2019,388],{},[362,2020,387],{},[18,2022,391,2023,395],{},[362,2024,394],{},[50,2026,399],{"id":398},[18,2028,402,2029,406],{},[22,2030,405],{},[18,2032,409],{},[50,2034,413],{"id":412},[18,2036,416,2037,420],{},[22,2038,419],{},[18,2040,423,2041,426,2043,430],{},[22,2042,78],{},[22,2044,429],{},[45,2046,434],{"id":433},[50,2048,438],{"id":437},[18,2050,441],{},[18,2052,444,2053,448],{},[362,2054,447],{},[18,2056,451,2057,455],{},[362,2058,454],{},[50,2060,459],{"id":458},[18,2062,462],{},[18,2064,465],{},[18,2066,468],{},[18,2068,471],{},[50,2070,475],{"id":474},[18,2072,478],{},[310,2074,2075,2079,2083,2087,2091],{},[313,2076,2077,485],{},[362,2078,447],{},[313,2080,2081,491],{},[362,2082,490],{},[313,2084,2085,497],{},[362,2086,496],{},[313,2088,2089,503],{},[362,2090,502],{},[313,2092,2093,509],{},[362,2094,508],{},[18,2096,512,2097,200],{},[362,2098,447],{},[50,2100,518],{"id":517},[18,2102,521,2103,525],{},[362,2104,524],{},[527,2106,530],{"id":529},[532,2108,2109],{"className":534,"code":535,"language":536,"meta":537,"style":537},[362,2110,2111,2115,2119,2123,2127,2131,2135,2139,2143],{"__ignoreMap":537},[541,2112,2113],{"class":543,"line":544},[541,2114,547],{},[541,2116,2117],{"class":543,"line":550},[541,2118,553],{},[541,2120,2121],{"class":543,"line":556},[541,2122,559],{},[541,2124,2125],{"class":543,"line":562},[541,2126,565],{},[541,2128,2129],{"class":543,"line":568},[541,2130,571],{},[541,2132,2133],{"class":543,"line":574},[541,2134,577],{},[541,2136,2137],{"class":543,"line":580},[541,2138,583],{},[541,2140,2141],{"class":543,"line":586},[541,2142,589],{},[541,2144,2145],{"class":543,"line":592},[541,2146,595],{},[18,2148,360,2149,601],{},[362,2150,600],{},[50,2152,605],{"id":604},[18,2154,608,2155,612],{},[362,2156,611],{},[18,2158,615],{},[532,2160,2161],{"className":618,"code":619,"language":620,"meta":537,"style":537},[362,2162,2163],{"__ignoreMap":537},[541,2164,2165],{"class":543,"line":544},[541,2166,619],{},[18,2168,629],{},[532,2170,2172],{"className":2171,"code":634,"language":635,"meta":537},[633],[362,2173,634],{"__ignoreMap":537},[18,2175,640,2176,644],{},[362,2177,643],{},[18,2179,647,2180,651],{},[362,2181,650],{},[18,2183,654],{},[532,2185,2186],{"className":618,"code":657,"language":620,"meta":537,"style":537},[362,2187,2188],{"__ignoreMap":537},[541,2189,2190],{"class":543,"line":544},[541,2191,657],{},[50,2193,667],{"id":666},[18,2195,670],{},[532,2197,2198],{"className":673,"code":674,"language":675,"meta":537,"style":537},[362,2199,2200,2204],{"__ignoreMap":537},[541,2201,2202],{"class":543,"line":544},[541,2203,682],{},[541,2205,2206],{"class":543,"line":550},[541,2207,687],{},[18,2209,690],{},[18,2211,693,2212,697,2214,700,2216,703],{},[362,2213,696],{},[362,2215,496],{},[362,2217,447],{},[18,2219,706],{},[18,2221,709],{},[50,2223,713],{"id":712},[18,2225,716],{},[18,2227,719],{},[18,2229,722],{},[45,2231,726],{"id":725},[50,2233,730],{"id":729},[18,2235,733],{},[18,2237,736],{},[310,2239,2240,2242,2244,2246,2248],{},[313,2241,741],{},[313,2243,744],{},[313,2245,747],{},[313,2247,750],{},[313,2249,753],{},[18,2251,756],{},[50,2253,760],{"id":759},[18,2255,763],{},[18,2257,766],{},[532,2259,2261],{"className":2260,"code":770,"language":635,"meta":537},[633],[362,2262,770],{"__ignoreMap":537},[527,2264,776],{"id":775},[18,2266,360,2267,781],{},[362,2268,776],{},[532,2270,2271],{"className":784,"code":785,"language":786,"meta":537,"style":537},[362,2272,2273,2277,2281,2285,2289,2293,2297,2301,2305,2309,2313,2317],{"__ignoreMap":537},[541,2274,2275],{"class":543,"line":544},[541,2276,793],{},[541,2278,2279],{"class":543,"line":550},[541,2280,798],{"emptyLinePlaceholder":8},[541,2282,2283],{"class":543,"line":556},[541,2284,803],{},[541,2286,2287],{"class":543,"line":562},[541,2288,808],{},[541,2290,2291],{"class":543,"line":568},[541,2292,813],{},[541,2294,2295],{"class":543,"line":574},[541,2296,818],{},[541,2298,2299],{"class":543,"line":580},[541,2300,823],{},[541,2302,2303],{"class":543,"line":586},[541,2304,828],{},[541,2306,2307],{"class":543,"line":592},[541,2308,833],{},[541,2310,2311],{"class":543,"line":836},[541,2312,839],{},[541,2314,2315],{"class":543,"line":842},[541,2316,845],{},[541,2318,2319],{"class":543,"line":848},[541,2320,851],{},[18,2322,854],{},[50,2324,858],{"id":857},[18,2326,861],{},[532,2328,2329],{"className":864,"code":865,"language":866,"meta":537,"style":537},[362,2330,2331,2335,2339,2343,2347],{"__ignoreMap":537},[541,2332,2333],{"class":543,"line":544},[541,2334,873],{},[541,2336,2337],{"class":543,"line":550},[541,2338,798],{"emptyLinePlaceholder":8},[541,2340,2341],{"class":543,"line":556},[541,2342,882],{},[541,2344,2345],{"class":543,"line":562},[541,2346,798],{"emptyLinePlaceholder":8},[541,2348,2349],{"class":543,"line":568},[541,2350,891],{},[18,2352,894],{},[18,2354,897,2355,901,2357,905,2359,909],{},[362,2356,900],{},[362,2358,904],{},[362,2360,908],{},[50,2362,913],{"id":912},[18,2364,916],{},[532,2366,2367],{"className":618,"code":919,"language":620,"meta":537,"style":537},[362,2368,2369],{"__ignoreMap":537},[541,2370,2371],{"class":543,"line":544},[541,2372,919],{},[18,2374,928],{},[532,2376,2377],{"className":618,"code":931,"language":620,"meta":537,"style":537},[362,2378,2379],{"__ignoreMap":537},[541,2380,2381],{"class":543,"line":544},[541,2382,931],{},[18,2384,940],{},[532,2386,2388],{"className":2387,"code":944,"language":635,"meta":537},[633],[362,2389,944],{"__ignoreMap":537},[18,2391,949],{},[532,2393,2395],{"className":2394,"code":953,"language":635,"meta":537},[633],[362,2396,953],{"__ignoreMap":537},[50,2398,959],{"id":958},[18,2400,962,2401,965],{},[362,2402,776],{},[532,2404,2405],{"className":864,"code":968,"language":866,"meta":537,"style":537},[362,2406,2407,2411,2415,2419,2423],{"__ignoreMap":537},[541,2408,2409],{"class":543,"line":544},[541,2410,873],{},[541,2412,2413],{"class":543,"line":550},[541,2414,798],{"emptyLinePlaceholder":8},[541,2416,2417],{"class":543,"line":556},[541,2418,882],{},[541,2420,2421],{"class":543,"line":562},[541,2422,798],{"emptyLinePlaceholder":8},[541,2424,2425],{"class":543,"line":568},[541,2426,991],{},[18,2428,994],{},[532,2430,2432],{"className":2431,"code":998,"language":635,"meta":537},[633],[362,2433,998],{"__ignoreMap":537},[18,2435,1003],{},[18,2437,1006],{},[45,2439,1010],{"id":1009},[18,2441,1013],{},[18,2443,1016,2444,1020,2446,1020,2448,1020,2450,1030],{},[362,2445,1019],{},[362,2447,1023],{},[362,2449,1026],{},[362,2451,1029],{},[18,2453,1033],{},[18,2455,1036],{},[18,2457,1039],{},[310,2459,2460,2462,2464,2466,2468],{},[313,2461,1044],{},[313,2463,1047],{},[313,2465,1050],{},[313,2467,1053],{},[313,2469,1056],{},[18,2471,1059],{},[18,2473,1062],{},[50,2475,1066],{"id":1065},[18,2477,1069],{},[18,2479,1072,2480,1076],{},[362,2481,1075],{},[18,2483,615],{},[532,2485,2486],{"className":618,"code":1081,"language":620,"meta":537,"style":537},[362,2487,2488,2492,2496,2500],{"__ignoreMap":537},[541,2489,2490],{"class":543,"line":544},[541,2491,1088],{},[541,2493,2494],{"class":543,"line":550},[541,2495,1093],{},[541,2497,2498],{"class":543,"line":556},[541,2499,1098],{},[541,2501,2502],{"class":543,"line":562},[541,2503,1103],{},[18,2505,1106],{},[532,2507,2509],{"className":2508,"code":1110,"language":635,"meta":537},[633],[362,2510,1110],{"__ignoreMap":537},[18,2512,1115],{},[532,2514,2516],{"className":2515,"code":1119,"language":635,"meta":537},[633],[362,2517,1119],{"__ignoreMap":537},[18,2519,1124],{},[18,2521,1127],{},[532,2523,2524],{"className":864,"code":1130,"language":866,"meta":537,"style":537},[362,2525,2526,2530,2534,2538,2542,2546,2550,2554,2558,2562,2566,2570,2574,2578,2582,2586],{"__ignoreMap":537},[541,2527,2528],{"class":543,"line":544},[541,2529,1137],{},[541,2531,2532],{"class":543,"line":550},[541,2533,798],{"emptyLinePlaceholder":8},[541,2535,2536],{"class":543,"line":556},[541,2537,1146],{},[541,2539,2540],{"class":543,"line":562},[541,2541,798],{"emptyLinePlaceholder":8},[541,2543,2544],{"class":543,"line":568},[541,2545,1155],{},[541,2547,2548],{"class":543,"line":574},[541,2549,798],{"emptyLinePlaceholder":8},[541,2551,2552],{"class":543,"line":580},[541,2553,1164],{},[541,2555,2556],{"class":543,"line":586},[541,2557,1169],{},[541,2559,2560],{"class":543,"line":592},[541,2561,1174],{},[541,2563,2564],{"class":543,"line":836},[541,2565,1179],{},[541,2567,2568],{"class":543,"line":842},[541,2569,798],{"emptyLinePlaceholder":8},[541,2571,2572],{"class":543,"line":848},[541,2573,873],{},[541,2575,2576],{"class":543,"line":1190},[541,2577,798],{"emptyLinePlaceholder":8},[541,2579,2580],{"class":543,"line":1195},[541,2581,882],{},[541,2583,2584],{"class":543,"line":1200},[541,2585,798],{"emptyLinePlaceholder":8},[541,2587,2588],{"class":543,"line":1205},[541,2589,1208],{},[18,2591,1211],{},[18,2593,1214],{},[18,2595,1217],{},[45,2597,1221],{"id":1220},[18,2599,1224],{},[18,2601,1227],{},[532,2603,2605],{"className":2604,"code":1231,"language":635,"meta":537},[633],[362,2606,1231],{"__ignoreMap":537},[18,2608,1236],{},[532,2610,2612],{"className":2611,"code":1240,"language":635,"meta":537},[633],[362,2613,1240],{"__ignoreMap":537},[18,2615,1245,2616,1249,2618,200],{},[362,2617,1248],{},[362,2619,1252],{},[18,2621,1255],{},[50,2623,1259],{"id":1258},[18,2625,1262,2626,1266],{},[22,2627,1265],{},[18,2629,1269,2630,25,2632,1276],{},[22,2631,1272],{},[22,2633,1275],{},[18,2635,1279],{},[18,2637,1282,2638,25,2640,1287],{},[22,2639,1272],{},[22,2641,1275],{},[50,2643,1291],{"id":1290},[18,2645,1294,2646,1298],{},[362,2647,1297],{},[532,2649,2650],{"className":784,"code":1301,"language":786,"meta":537,"style":537},[362,2651,2652,2656,2660,2664,2668,2672,2676,2680,2684,2688,2692,2696,2700,2704,2708,2712,2716,2720,2724,2728,2732,2736,2740,2744,2748,2752,2756,2760,2764,2768,2772,2776,2780,2784,2788,2792,2796,2800,2804,2808,2812,2816,2820],{"__ignoreMap":537},[541,2653,2654],{"class":543,"line":544},[541,2655,1308],{},[541,2657,2658],{"class":543,"line":550},[541,2659,1313],{},[541,2661,2662],{"class":543,"line":556},[541,2663,1318],{},[541,2665,2666],{"class":543,"line":562},[541,2667,1323],{},[541,2669,2670],{"class":543,"line":568},[541,2671,798],{"emptyLinePlaceholder":8},[541,2673,2674],{"class":543,"line":574},[541,2675,1332],{},[541,2677,2678],{"class":543,"line":580},[541,2679,798],{"emptyLinePlaceholder":8},[541,2681,2682],{"class":543,"line":586},[541,2683,1341],{},[541,2685,2686],{"class":543,"line":592},[541,2687,1346],{},[541,2689,2690],{"class":543,"line":836},[541,2691,1351],{},[541,2693,2694],{"class":543,"line":842},[541,2695,1356],{},[541,2697,2698],{"class":543,"line":848},[541,2699,798],{"emptyLinePlaceholder":8},[541,2701,2702],{"class":543,"line":1190},[541,2703,1365],{},[541,2705,2706],{"class":543,"line":1195},[541,2707,1370],{},[541,2709,2710],{"class":543,"line":1200},[541,2711,1375],{},[541,2713,2714],{"class":543,"line":1205},[541,2715,1380],{},[541,2717,2718],{"class":543,"line":1383},[541,2719,1386],{},[541,2721,2722],{"class":543,"line":1389},[541,2723,1392],{},[541,2725,2726],{"class":543,"line":1395},[541,2727,798],{"emptyLinePlaceholder":8},[541,2729,2730],{"class":543,"line":1400},[541,2731,1403],{},[541,2733,2734],{"class":543,"line":1406},[541,2735,1409],{},[541,2737,2738],{"class":543,"line":1412},[541,2739,1415],{},[541,2741,2742],{"class":543,"line":1418},[541,2743,1421],{},[541,2745,2746],{"class":543,"line":1424},[541,2747,798],{"emptyLinePlaceholder":8},[541,2749,2750],{"class":543,"line":1429},[541,2751,1432],{},[541,2753,2754],{"class":543,"line":1435},[541,2755,1438],{},[541,2757,2758],{"class":543,"line":1441},[541,2759,1444],{},[541,2761,2762],{"class":543,"line":1447},[541,2763,1450],{},[541,2765,2766],{"class":543,"line":1453},[541,2767,1456],{},[541,2769,2770],{"class":543,"line":1459},[541,2771,1462],{},[541,2773,2774],{"class":543,"line":1465},[541,2775,1468],{},[541,2777,2778],{"class":543,"line":1471},[541,2779,798],{"emptyLinePlaceholder":8},[541,2781,2782],{"class":543,"line":1476},[541,2783,1479],{},[541,2785,2786],{"class":543,"line":1482},[541,2787,1485],{},[541,2789,2790],{"class":543,"line":1488},[541,2791,1491],{},[541,2793,2794],{"class":543,"line":1494},[541,2795,1497],{},[541,2797,2798],{"class":543,"line":1500},[541,2799,1370],{},[541,2801,2802],{"class":543,"line":1505},[541,2803,1508],{},[541,2805,2806],{"class":543,"line":1511},[541,2807,1514],{},[541,2809,2810],{"class":543,"line":1517},[541,2811,1491],{},[541,2813,2814],{"class":543,"line":1522},[541,2815,1525],{},[541,2817,2818],{"class":543,"line":1528},[541,2819,798],{"emptyLinePlaceholder":8},[541,2821,2822],{"class":543,"line":1533},[541,2823,1536],{},[18,2825,1539],{},[18,2827,1542,2828,1546],{},[362,2829,1545],{},[18,2831,1549],{},[532,2833,2834],{"className":1552,"code":1553,"language":1554,"meta":537,"style":537},[362,2835,2836],{"__ignoreMap":537},[541,2837,2838],{"class":543,"line":544},[541,2839,1553],{},[18,2841,1563],{},[18,2843,1566],{},[532,2845,2847],{"className":2846,"code":1570,"language":635,"meta":537},[633],[362,2848,1570],{"__ignoreMap":537},[18,2850,1575],{},[532,2852,2854],{"className":2853,"code":1579,"language":635,"meta":537},[633],[362,2855,1579],{"__ignoreMap":537},[18,2857,360,2858,1587],{},[362,2859,1586],{},[18,2861,1590],{},[45,2863,1594],{"id":1593},[18,2865,1597],{},[18,2867,1600],{},[18,2869,1603],{},[18,2871,1606],{},[18,2873,1609],{},[18,2875,1612],{},[45,2877,1616],{"id":1615},[50,2879,1620],{"id":1619},[18,2881,1623],{},[50,2883,1627],{"id":1626},[18,2885,1630],{},[50,2887,1634],{"id":1633},[18,2889,1637],{},[50,2891,1641],{"id":1640},[18,2893,1644],{},[50,2895,1648],{"id":1647},[18,2897,1651,2898,1654],{},[362,2899,447],{},[50,2901,1658],{"id":1657},[18,2903,1661,2904,1664,2906,1667],{},[362,2905,496],{},[362,2907,447],{},[50,2909,1671],{"id":1670},[18,2911,1674,2912,1678],{},[22,2913,1677],{},[50,2915,1682],{"id":1681},[18,2917,1685],{},[50,2919,1689],{"id":1688},[18,2921,1692],{},[1694,2923,1696],{},{"title":537,"searchDepth":550,"depth":550,"links":2925},[2926,2937,2946,2953,2956,2960,2961],{"id":47,"depth":550,"text":48,"children":2927},[2928,2929,2930,2931,2932,2933,2934,2935,2936],{"id":52,"depth":556,"text":53},{"id":68,"depth":556,"text":69},{"id":82,"depth":556,"text":83},{"id":209,"depth":556,"text":210},{"id":294,"depth":556,"text":295},{"id":301,"depth":556,"text":302},{"id":378,"depth":556,"text":379},{"id":398,"depth":556,"text":399},{"id":412,"depth":556,"text":413},{"id":433,"depth":550,"text":434,"children":2938},[2939,2940,2941,2942,2943,2944,2945],{"id":437,"depth":556,"text":438},{"id":458,"depth":556,"text":459},{"id":474,"depth":556,"text":475},{"id":517,"depth":556,"text":518},{"id":604,"depth":556,"text":605},{"id":666,"depth":556,"text":667},{"id":712,"depth":556,"text":713},{"id":725,"depth":550,"text":726,"children":2947},[2948,2949,2950,2951,2952],{"id":729,"depth":556,"text":730},{"id":759,"depth":556,"text":760},{"id":857,"depth":556,"text":858},{"id":912,"depth":556,"text":913},{"id":958,"depth":556,"text":959},{"id":1009,"depth":550,"text":1010,"children":2954},[2955],{"id":1065,"depth":556,"text":1066},{"id":1220,"depth":550,"text":1221,"children":2957},[2958,2959],{"id":1258,"depth":556,"text":1259},{"id":1290,"depth":556,"text":1291},{"id":1593,"depth":550,"text":1594},{"id":1615,"depth":550,"text":1616,"children":2962},[2963,2964,2965,2966,2967,2968,2969,2970,2971],{"id":1619,"depth":556,"text":1620},{"id":1626,"depth":556,"text":1627},{"id":1633,"depth":556,"text":1634},{"id":1640,"depth":556,"text":1641},{"id":1647,"depth":556,"text":1648},{"id":1657,"depth":556,"text":1658},{"id":1670,"depth":556,"text":1671},{"id":1681,"depth":556,"text":1682},{"id":1688,"depth":556,"text":1689},{},{"title":12,"description":1748},{"id":2975,"title":2976,"author":13,"body":2977,"category":1745,"cover":3075,"date":3076,"description":3077,"extension":1749,"featured":3078,"isFeatured":1751,"meta":3079,"navigation":8,"path":3080,"preview":3081,"seo":3082,"stem":3083,"updated":1757,"__hash__":3084},"articles\u002Farticles\u002Fhow_to\u002F2026-07-19-how-to-run-openvpn-on-aws-in-10-minutes.md","How to run OpenVPN on AWS in 5 minutes",{"type":15,"value":2978,"toc":3073},[2979,2982,2987,2990,2993,2997,3000,3021,3025,3028,3049,3052,3055,3059,3062,3066],[18,2980,2981],{},"Setting up a VPN server used to take weeks t oget it right: fiddling with certificates, managing a CA, messing with iptables, and hoping it all works. This guide shows you how to get OpenVPN running in your own AWS account in about 5 minutes, and why doing it yourself beats renting one.",[2983,2984,2986],"h1",{"id":2985},"why-run-your-own-vpn-on-aws","Why run your own VPN on AWS",[18,2988,2989],{},"If you run stuff on AWS, you've got private subnets holding sensitive things, databases, admin panels, internal tools, that should never be public. The real question isn't keeping them private, but how your team gets to them. The answer: a VPN in a public subnet of your VPC. Your team connects to it, and those private subnets act like they're local. You control access with certs you issue, set expiration, and can revoke anytime someone leaves.",[18,2991,2992],{},"This setup works great for offices too. Rather than installing a VPN on each laptop, you just connect the office router to the gateway. That way, everyone in the office accesses AWS resources like they're local. One tunnel, no client setup, everyone behind the router is covered.",[2983,2994,2996],{"id":2995},"the-options","The options",[18,2998,2999],{},"You have three choices:",[3001,3002,3003,3009,3015],"ol",{},[313,3004,3005,3008],{},[22,3006,3007],{},"AWS Client VPN",", managed, but pricey. You pay per subnet per hour plus per connected client. A small team can rack up hundreds every month.",[313,3010,3011,3014],{},[22,3012,3013],{},"Build OpenVPN yourself",", launch an EC2, install OpenVPN, set up the CA, manage certs, and routing. Cheap except your time, and cert management never ends.",[313,3016,3017,3020],{},[22,3018,3019],{},"Prebuilt OpenVPN AMI from AWS Marketplace",", the sweet spot. Setup in 5 minutes, cert management baked in, no headaches.",[2983,3022,3024],{"id":3023},"the-5-minute-setup","The 5 minute setup",[18,3026,3027],{},"We built Valdras Gate for this. Self-hosted OpenVPN in your AWS account, no license limits, unlimited users. Here's how:",[3001,3029,3030,3040,3043,3046],{},[313,3031,3032,3033,200],{},"Subscribe at the ",[3034,3035,3039],"a",{"href":3036,"rel":3037},"https:\u002F\u002Faws.amazon.com\u002Fmarketplace\u002Fpp\u002Fprodview-ladycxtlsdnd6",[3038],"nofollow","Valdras Gate AWS Marketplace page",[313,3041,3042],{},"Launch the AMI in your VPC. A t3.nano handles a small team just fine, the network card is the only real bottleneck.",[313,3044,3045],{},"After boot, SSH in and create your first user with one CLI command. The user profile with embedded certs is emailed automatically.",[313,3047,3048],{},"Import the profile into any OpenVPN client and connect.",[18,3050,3051],{},"Done. No license servers, no fees per user, and the certificates manage themselves. User management is just a few CLI commands: create, list, revoke users. Each profile must have an expiration date set at creation, no exceptions. This is your safety net: if you forget to revoke a contractor's access, their certificate simply stops working once it expires. The server blocks it during handshake, so no manual cleanup is needed.",[18,3053,3054],{},"So, what about legit users who need ongoing access? They don't get locked out. Just enable auto-renewal for their profiles. The server will generate a new profile before the old one expires and email it with instructions. No one needs to keep track of expiry dates or submit tickets when VPN stops working Monday morning.",[2983,3056,3058],{"id":3057},"the-cost","The cost",[18,3060,3061],{},"Valdras Gate is a straightforward $99 a month, no matter your user count. Other VPNs on AWS Marketplace charge per user and force you to manually renew profiles every year. Once you have more than a few users, costs skyrocket and maintaining profiles becomes a huge headache. With our flat fee and automatic renewals, those issues just vanish.",[2983,3063,3065],{"id":3064},"closing-thoughts","Closing thoughts",[18,3067,3068,3069,200],{},"VPNs should be boring. Set it up once, let it run, revoke certs when people leave. Running your own in AWS means you control security, not someone else. If you want the 5-minute setup instead of a weekend stress fest, ",[3034,3070,3072],{"href":3036,"rel":3071},[3038],"Valdras Gate is on AWS Marketplace",{"title":537,"searchDepth":550,"depth":550,"links":3074},[],"\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-run-openvpn-on-aws\u002Fcover.jpg","2026-07-19","Why running your own OpenVPN server in your AWS account beats commercial VPNs and managed offerings - and how to get one running in about 5 minutes.","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-run-openvpn-on-aws\u002Ffeatured.jpg",{},"\u002Farticles\u002Fhow_to\u002F2026-07-19-how-to-run-openvpn-on-aws-in-10-minutes","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-run-openvpn-on-aws\u002Fpreview.jpg",{"title":2976,"description":3077},"articles\u002Fhow_to\u002F2026-07-19-how-to-run-openvpn-on-aws-in-10-minutes","kvZWp9soacdiSooskFBxyCh5W5lREoUQHbCz7JcsqMo",{"id":3086,"title":3087,"author":13,"body":3088,"category":1745,"cover":3212,"date":3213,"description":3214,"extension":1749,"featured":3215,"isFeatured":8,"meta":3216,"navigation":8,"path":3217,"preview":3218,"seo":3219,"stem":3220,"updated":3221,"__hash__":3222},"articles\u002Farticles\u002Fhow_to\u002F2020-12-19-how-to-lower-aws-costs.md","How to lower AWS Costs",{"type":15,"value":3089,"toc":3206},[3090,3098,3102,3105,3109,3112,3115,3118,3126,3130,3133,3136,3139,3147,3151,3154,3157,3160,3164,3167,3171,3174,3178,3181,3185,3188,3191,3195,3198],[18,3091,3092,3093,3097],{},"This article is meant for CEOs, CTOs, and Managers. The goal is to give a better understanding of how to lower AWS costs by answering a common raised question by clients: ",[3094,3095,3096],"em",{},"What is the simplest way to lower the AWS bill","?",[2983,3099,3101],{"id":3100},"the-mysticism","The mysticism",[18,3103,3104],{},"AWS costs are wrapped in mysticism due to mysterious practices by companies that specialize in this field. The reality is simpler than you might think, otherwise these companies would not hide behind big words and convoluted explanations.",[2983,3106,3108],{"id":3107},"the-aws-billing-page","The AWS Billing Page",[18,3110,3111],{},"AWS provides you with a very simple to use billing page, which breaks down all your costs based on the service, and the region. This makes it easy to find the biggest expense in the account.",[18,3113,3114],{},"More importantly if you have an organization account and under that you have dozens of other AWS accounts, the billing page also provides you with a break down based on the individual account under the organization. This makes it simple to find the account that is generating the biggest costs, while allowing you to then drill down to the service, and region.",[18,3116,3117],{},"The billing page is the most important thing to use when it comes to getting an idea of what is going on in the account. Once you know where the money goes, we can go into the details and figure out if there is something that can be changed to lower the monthly bill.",[18,3119,3120,3121,3125],{},"By the way: if you want to ",[3034,3122,3124],{"href":3123},"\u002Farticles\u002Fknowledge\u002F2020-03-15-the-benefits-of-aws-organizations\u002F","learn more about the benefits of AWS Organizations",", check out the article.",[45,3127,3129],{"id":3128},"pay-by-the-hour-services","Pay-By-The-Hour Services",[18,3131,3132],{},"The majority of the costs in your organization are going to come from EC2, RDS and similar Pay-By-The-Hour type services. These are the most used services, and most importantly AWS charges you for these services the moment they are turned on, regardless of the load.",[18,3134,3135],{},"The majority of the time, these services are turned on by employees temporarily just to perform a test, or run a one time job, but will forget to turn them off. Services could be left on for years, while your bank account is being drained for servers that have 0.45% CPU time.",[18,3137,3138],{},"Thankfully this problem can not only can be quickly identified, but also be quickly solved by just simply turning off those unused servers. The simplest approach is to stop all the servers with less than 1% CPU time in the case of Linux, and 3% in the case of Windows instances. This approach allows you to stop paying for the servers, but also turn them back on when they are actually needed (Because if they are, someone somewhere should start screaming).",[18,3140,3141,3142,3146],{},"On the other hand, if your servers are needed, then you are probably not taking advantage of the commitment discounts AWS provides. With Savings Plans and Reserved Instances, instead of paying by the hour, you commit for one or three years and ",[3034,3143,3145],{"href":3144},"\u002Farticles\u002Fhow_to\u002F2020-03-15-how-to-lower-ec2-costs\u002F","lower your bill by up to 72%",", check the article to find out more.",[45,3148,3150],{"id":3149},"serverless-services","Serverless Services",[18,3152,3153],{},"The next big contributors are all of the serverless technologies that AWS offers. In contrast to the pay-by-the-hour onset, this one generates a charge when actually used. This means that there might not be a quick fix. To reduce the price for these services, you’ll have to change how you use them. In the case of S3 it might be as simple as enabling Intelligent-Tiering on a S3 bucket, but in other cases you might have to change the code of the application, for example how DynamoDB is being used.",[18,3155,3156],{},"Since we are discussing DynamoDB already - when you use this NoSQL database in On-Demand mode, you get charged by how many queries to it you make, and also how much data is being moved back and forth. If the application using this services makes lots of poorly constructed requests, or the data is structured in a way where the data transfer is high, then you'll pay incredible amount of money on a daily basis.",[18,3158,3159],{},"In situations similar to these, you’d need an expert to look in to the problem, and come up with a solution, and then this solution will have to be implemented correctly to lower the bill.",[2983,3161,3163],{"id":3162},"prevention-mechanisms","Prevention Mechanisms",[18,3165,3166],{},"Overall the best approach is to always educate people to help them make better decisions when they use all that AWS has to offer. There also some simple ways to remind them of what they have learned.",[45,3168,3170],{"id":3169},"for-pay-by-the-hour-services","For:  Pay-By-The-Hour Services",[18,3172,3173],{},"The IAM services has the idea of Policies, this are documents that specify what a IAM User can do in the AWS account. It can be as simple as the user has only access to EC2 Instances, or you can extend it to include which type of instances can be launched by the user, and even specify the region in which they can do that. With a policy like this you can be confident that nobody will launch expensive instances without permission. This is true for any service that is pay-by-the-hour.",[45,3175,3177],{"id":3176},"for-serverless-services","For:  Serverless Services",[18,3179,3180],{},"Sadly, there is no way to have a policy that prevents developers from making queries the wrong way, or storing data the wrong way. The best solution here is to train the team so they can learn all the best practices for a given AWS Service.",[2983,3182,3184],{"id":3183},"good-monitoring","Good Monitoring",[18,3186,3187],{},"Lastly, a big part of keeping a close eye on the AWS expenses is good monitoring. Each service that is being used should have CloudWatch Alarms monitoring thresholds, and sending notifications when there is something that goes over your set limits. Of course in some cases this takes some effort to get the threshold just right, but once you do, you’ll know exactly when and what is causing a problem.",[18,3189,3190],{},"CloudWatch alarms are fine for technical stuff, but for costs AWS has two better tools. AWS Budgets let you set a monthly limit and alert you if you go over or if forecasted spend looks wrong. You can even set it to automatically block new resource creation if you hit your budget. Cost Anomaly Detection uses machine learning to spot weird spending patterns and flags them by dollar impact, broken down by service, account, and region. Both take just a few minutes to set up and are free. No more surprises on your bill.",[2983,3192,3194],{"id":3193},"to-sum-it-up","To Sum it Up",[18,3196,3197],{},"Depending on your situation, I hope that you’ll be able to (even today!) lower your AWS bill substantially. If not, you should now have a good understanding on what to look for, and what to ask the people in your organization.",[18,3199,3200,3201,3205],{},"If you would rather have someone who has done this dozens of times go through your account, I offer a ",[3034,3202,3204],{"href":3203},"\u002Fconsulting\u002F","fixed-price AWS audit"," that covers costs, security, and architecture in one report.",{"title":537,"searchDepth":550,"depth":550,"links":3207},[3208,3209,3210,3211],{"id":3128,"depth":550,"text":3129},{"id":3149,"depth":550,"text":3150},{"id":3169,"depth":550,"text":3170},{"id":3176,"depth":550,"text":3177},"\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-lower-aws-costs\u002Fcover.jpg","2020-12-19","Where AWS money actually goes and how to stop the bleeding - billing page, idle servers, Savings Plans, and free alerting. A guide for CEOs and CTOs.","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-lower-aws-costs\u002Ffeatured.jpg",{},"\u002Farticles\u002Fhow_to\u002F2020-12-19-how-to-lower-aws-costs","\u002Fpublic\u002Fimg\u002Farticles\u002Fhow-to-lower-aws-costs\u002Fpreview.jpg",{"title":3087,"description":3214},"articles\u002Fhow_to\u002F2020-12-19-how-to-lower-aws-costs","2026-07-18","-i4EXiQO3YgSZQmbUzmS9wWRV6--_TDlCmanNcdLVes",1786689776784]