Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale
1.0.0-dev.7
dotnet add package Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale --version 1.0.0-dev.7
NuGet\Install-Package Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale -Version 1.0.0-dev.7
<PackageReference Include="Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale" Version="1.0.0-dev.7" />
<PackageVersion Include="Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale" Version="1.0.0-dev.7" />
<PackageReference Include="Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale" />
paket add Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale --version 1.0.0-dev.7
#r "nuget: Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale, 1.0.0-dev.7"
#:package Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale@1.0.0-dev.7
#addin nuget:?package=Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale&version=1.0.0-dev.7&prerelease
#tool nuget:?package=Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale&version=1.0.0-dev.7&prerelease
Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale
.NET Aspire hosting extensions for publishing Tailscale Kubernetes Operator resources. This package adds resource-local Tailscale service intent and Kubernetes environment resource-definition helpers.
Installation
dotnet add package Arkanis.Aspire.Hosting.Extensions.Kubernetes.Tailscale
Quick Start
Configure the tailnet once when generated Tailscale Ingress hosts should use the default <tailnet>.ts.net MagicDNS suffix.
With the resource name web, the following example emits an Ingress host of web-staging.my-tailnet.ts.net.
using Aspire.Hosting;
using Aspire.Hosting.Extensions.Kubernetes;
using Aspire.Hosting.Extensions.Kubernetes.Tailscale;
var builder = DistributedApplication.CreateBuilder(args);
var web = builder.AddProject<Projects.Web>("web");
var kubernetes = builder.AddKubernetesEnvironment("kubernetes");
kubernetes.AddTailscale(tailscale => tailscale
.WithTailnet("my-tailnet")
.WithHostnameSuffix("staging")
.ForResource(web, resource => resource.ExposeIngress("web-tailscale", ingress => ingress
.WithProxyGroup("staging-k8s-ingress-proxies")
.ToGeneratedService("http"))));
builder.Build().Run();
Hostnames
HostnamePrefix and HostnameSuffix decorate the generated short MagicDNS name.
By default, the generated short name is based on the Aspire resource name, so citizenid-dashboard with HostnameSuffix set to staging becomes citizenid-dashboard-staging.
Ingress resource names are not included in the generated hostname.
WithHostnameBase("dashboard") replaces only the resource-name part of the generated short MagicDNS name.
HostnamePrefix and HostnameSuffix still apply, so WithHostnameSuffix("staging") plus WithHostnameBase("dashboard") becomes dashboard-staging.
Use this when a Service or Ingress needs a shorter stable base while still sharing the environment naming convention.
WithTailnet("my-tailnet") expands generated Ingress MagicDNS names to fully qualified hosts under my-tailnet.ts.net.
The same setting accepts my-tailnet.ts.net when configuration already stores the full DNS suffix.
For citizenid-dashboard with HostnameSuffix set to staging, the generated Ingress host becomes citizenid-dashboard-staging.my-tailnet.ts.net.
WithMagicDnsName("dashboard") overrides only the short MagicDNS name.
For Ingress exposure, the configured tailnet still expands it to dashboard.my-tailnet.ts.net.
For Service exposure, the value remains the short name written to tailscale.com/hostname.
WithHostname("dashboard.internal.example.com") is an exact override.
It is emitted unchanged and never receives the configured tailnet suffix.
Use it when the final Kubernetes host is already known or must not be a Tailscale MagicDNS name.
Hostname resolution precedence is exact Hostname, then exact-short MagicDnsName, then generated HostnamePrefix plus HostnameBase or resource name plus HostnameSuffix.
Dedicated Service
Use a dedicated Service when only one port should be reachable through Tailscale.
The tailnet setting does not append .ts.net to Service hostnames because Tailscale Service annotations request a machine name.
kubernetes.AddTailscale(tailscale => tailscale
.WithHostnameSuffix("staging")
.ForResource(new ResourceName("citizenid-dashboard"), resource => resource.ExposeService(service => service
.AsStandalone()
.WithHostnameBase("dashboard")
.EmitDedicatedService("dashboard-ingress-tailscale", dedicated => dedicated
.WithAspireResourceSelector(new ResourceName("citizenid-dashboard"))
.WithPort(80, 18888)))));
Ingress
Use a Tailscale Ingress when the workload should be exposed through Kubernetes Ingress resources.
When a tailnet is configured, the same fully qualified host is emitted into spec.rules[0].host and spec.tls[0].hosts[0].
secretName is always emitted and defaults to {ingressName}-tls, although Tailscale manages the certificate itself.
kubernetes.AddTailscale(tailscale => tailscale
.WithTailnet("my-tailnet")
.WithHostnameSuffix("staging")
.ForResource(web, resource => resource.ExposeIngress("web-tailscale", ingress => ingress
.WithHostnameBase("web")
.WithProxyGroup("staging-k8s-ingress-proxies")
.WithFunnel()
.WithInClusterMagicDnsForwarding()
.ToGeneratedService("http"))));
This produces the important Ingress shape below.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-tailscale
annotations:
tailscale.com/proxy-group: staging-k8s-ingress-proxies
tailscale.com/funnel: "true"
tailscale.com/experimental-forward-cluster-traffic-via-ingress: "true"
spec:
ingressClassName: tailscale
rules:
- host: web-staging.my-tailnet.ts.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
name: http
tls:
- hosts:
- web-staging.my-tailnet.ts.net
secretName: web-tailscale-tls
Use WithTlsSecretName("custom-tls") when a chart convention needs a different placeholder Secret name.
Configuration
Configuration can provide tailnet, hostnames, tags, ProxyGroups, Ingress options, and shared defaults while code supplies missing selectors or port safety.
kubernetes.AddTailscale(
builder.Configuration,
tailscale => tailscale.ForResource(web, resource => resource.ExposeService(service => service
.EmitDedicatedService("web-tailscale", dedicated => dedicated
.WithPort(80, 8080)))));
{
"Kubernetes": {
"Tailscale": {
"Tailnet": "my-tailnet",
"HostnameSuffix": "staging",
"Resources": {
"web": {
"Ingresses": {
"web-tailscale": {
"Enabled": true,
"ProxyGroup": "staging-k8s-ingress-proxies",
"HostnameBase": "web-admin",
"Funnel": true,
"ForwardClusterTrafficViaIngress": true,
"TlsSecretName": "web-admin-tailscale-tls"
}
},
"Service": {
"Enabled": true,
"HostnameBase": "web-service",
"DedicatedService": {
"Enabled": true,
"ServiceName": "web-tailscale"
}
}
}
}
}
}
}
In this configuration, the Ingress host is web-admin-staging.my-tailnet.ts.net.
The Service hostname annotation is web-service-staging.
Scope
This package emits Tailscale Kubernetes Operator resource intent during Aspire publish. It does not install the operator, create OAuth credentials, create or configure tailnets, or apply generated manifests to a live cluster.
Dependency
This package references Arkanis.Aspire.Hosting.Extensions.Kubernetes.
Repository
Source, issues, and release workflow details are available at https://github.com/ArkanisCorporation/Aspire.Hosting.Extensions.Kubernetes.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Arkanis.Aspire.Hosting.Extensions.Kubernetes (>= 1.0.0-dev.7)
- Aspire.Hosting (>= 13.4.6)
- Aspire.Hosting.Kubernetes (>= 13.4.6-preview.1.26319.6)
- Microsoft.Extensions.Configuration (>= 10.0.9)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Logging (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- YamlDotNet (>= 18.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-dev.7 | 81 | 7/5/2026 |
| 1.0.0-dev.6 | 52 | 7/5/2026 |
| 1.0.0-dev.5 | 72 | 7/4/2026 |
| 1.0.0-dev.4 | 70 | 7/3/2026 |
| 1.0.0-dev.3 | 57 | 7/2/2026 |
| 1.0.0-dev.2 | 247 | 6/16/2026 |
| 1.0.0-dev.1 | 80 | 6/11/2026 |