Skip to content

Certificate

Source: src/Fly/Certificate.ts

A Fly.Certificate covers a hostname on an App. Default kind is "acme" (Let’s Encrypt). "custom" uploads a PEM.

IPs and certificates attach to the App. A Service publishes ports. Fly’s proxy terminates TLS on 443 once the certificate is configured.

Request Let’s Encrypt for a hostname. The Service does not change. Yield the certificate in the Stack. Point DNS at the App.

export const Www = Fly.Certificate("Www", {
app: Site,
hostname: "www.example.com",
});

Point an A record at a shared_v4 IpAssignment and an AAAA at v6. Plus whatever dnsRequirements lists for the ACME challenge. Alchemy re-checks via checkAppCertificate while configured is false.

Observed attrs include status, configured, acmeRequested, dnsRequirements, and validation.

export default Alchemy.Stack(
"MyApp",
{ providers: Fly.providers(), state: Alchemy.localState() },
Effect.gen(function* () {
const api = yield* Api;
const ip = yield* PublicIp;
const v6 = yield* V6;
const www = yield* Www;
return {
url: api.url,
ip: ip.ip,
v6: v6.ip,
dns: www.dnsRequirements,
};
}),
);

"custom" uploads fullchain and privateKey. Wrap the key with Redacted.make so it never logs. Never stored in attributes. Updating the PEM re-uploads in place.

export const Www = Fly.Certificate("Www", {
app: Site,
hostname: "www.example.com",
kind: "custom",
fullchain: pem,
privateKey: Redacted.make(key),
});