Multitenant
This might not be as relevant for self-hosted services, but for anyone providing software as a service and offering dedicated URL paths or subdomains for individual users, after deciding whether to use subdomains (e.g. https://<user>.domain.com
) or paths (e.g. https://domain.com/<user>
), the question of how to route traffic becomes important.
The first scheme allows natural mapping to individual host machines, since on DNS the subdomain can be managed with an A
record. Handling paths, on the other hand, can be trickier. For instance, in CloudFlare, you cannot just tunnel things to a subservice — the path here just provides some sort of submapping/filtering and must be handled by the server (i.e. the server program must explicitly handle /path
).
It's said that when using ASP.NET Core, one can make use of YARP for easier reverse proxy implementation instead of rolling a custom one.
Lambda
I've had fairly smooth experience with AWS Lambda before for scheduling a Python script every 15 days — providing custom libraries is a bit tricky with .zip
upload, but otherwise the service runs happily and freely for the purpose.
Here at Methodox, we absolutely prefer everything in native C#, as the entire Divooka ecosystem is C#-native. As it turns out, shipping Lambda functions with the .NET runtime is even easier than dealing with Python — since for any "platform-dependent" C# (.NET 8) distribution, all dependencies are just regular DLL files, and uploading it as a plain .zip
is as easy as it gets.
The AWS C# templates provide a straightforward starting point but are mostly for configuring assembly-level JSON serialization rules.
using Amazon.Lambda.Core;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
public class Function
{
public async Task<string> FunctionHandler(ILambdaContext context)
{
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<link href="style.css" rel="stylesheet" />
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
""";
}
}
Here is a function expecting a JSON payload (e.g. in POST):
using Amazon.Lambda.Core;
using OpenAI.Chat;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
public class Function
{
private readonly ChatClient _chatClient;
public Function()
{
string? apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
if (string.IsNullOrEmpty(apiKey))
throw new InvalidOperationException("Environment variable OPENAI_API_KEY is not set.");
// Initialize ChatClient for the gpt-3.5-turbo model
_chatClient = new ChatClient(model: "gpt-3.5-turbo", apiKey: apiKey);
}
public async Task<string> FunctionHandler(Input input, ILambdaContext context)
{
if (input == null || string.IsNullOrEmpty(input.Prompt))
throw new ArgumentException("Input must contain a non-empty Prompt.", nameof(input));
// Call OpenAI and return the first chunk of text
System.ClientModel.ClientResult<ChatCompletion> completion = await _chatClient.CompleteChatAsync(input.Prompt);
return completion.Value.Content[0].Text;
}
}
/// <summary>
/// JSON input schema for the Lambda function.
/// </summary>
public class Input
{
public string Prompt { get; set; } = string.Empty;
}
API Gateway
AWS offers a few similar platforms for front-facing services, and at a glance it can be a bit confusing, but it all makes a lot of sense when understood properly:
- Lambda is where the runtime is hosted and where things actually get executed.
- API Gateway comes with handy path configuration and response header overrides, and is used to aggregate/consume different services and expose them as structured endpoints.
- CloudFront is for CDN and supposedly provides better caching, though I'm not super clear on its features/architecture yet.
With these technologies, everything is supposed to be API-controllable, with no need for a single local server or explicit proxy handling — just do some configuration in the console.
Conclusion
I think this is as big a discovery as CloudFlare tunneling, and it immediately opens new doors. This setup should provide enough infrastructure for a barebone multitenant service.
What's more, the free-tier nature of many AWS services — including Lambda, API Gateway, DynamoDB, and CloudFront — enables some very creative combinations when it comes to service/endpoint distributions, especially during development or for distributed purposes at any scale.
Summary of new capabilities we've discovered over the past few weeks:
- CloudFlare for tunneling: allows local dev server deployment.
- AWS Lambda: serverless workloads with dynamic responses. Use for websites and APIs.
- API Gateway: effectively enables multitenant setup.
Top comments (0)