Add site to Cloudflare
In this tutorial, you will go through step-by-step instructions to bring an existing site to Cloudflare using Pulumi Infrastructure as Code (IaC) so that you can become familiar with the resource management lifecycle. In particular, you will create a Zone and a DNS record to resolve your newly added site. This tutorial adopts the IaC principle to complete the steps listed in the Add site tutorial.
Before you begin
Ensure you have:
- A Cloudflare account and API Token with permission to edit the resources in this tutorial. If you need to, sign up for a Cloudflare account before continuing. Your token must have:
Zone-Zone-Edit
permissionZone-DNS-Edit
permissioninclude-All zones from an account-<your account>
zone resource
- A Pulumi Cloud account. You can sign up for an always-free, individual tier.
- The Pulumi CLI is installed on your machine.
- A Pulumi-supported programming language is configured. (TypeScript, JavaScript, Python, Go, .NET, Java, or use YAML)
- A domain name. You may use
example.com
to complete the tutorial.
Initialize Pulumi
a. Create a directory
Use a new and empty directory for this tutorial.
$ mkdir addsite-cloudflare
$ cd addsite-cloudflare
b. Login
At the prompt, press Enter to log into your Pulumi Cloud account via the browser. Alternatively, you may provide a Pulumi Cloud access token.
$ pulumi login
c. Create a program
To create a program, select your language of choice and run the pulumi
command:
$ pulumi new javascript --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new typescript --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new python --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new go --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new java --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new csharp --name addsite-cloudflare --yes
# wait a few seconds while the project is initialized
$ pulumi new yaml --name addsite-cloudflare --yes
d. Save your settings
You will need:
- Your Cloudflare account ID.
- A valid Cloudflare API token.
- A domain. For instance,
example.com
.
# Define an ESC Environment name
$ E=my-dev-env
# Create a new Pulumi ESC Environment
$ pulumi config env init --env $E --yes --stack dev
# Replace API_TOKEN with your Cloudflare API Token
$ pulumi env set $E --secret pulumiConfig.cloudflare:apiToken API_TOKEN
# Replace abc123 with your Cloudflare Account ID
$ pulumi env set $E --plaintext pulumiConfig.accountId abc123
# Replace example.com with your registered domain, or leave as is
$ pulumi env set $E --plaintext pulumiConfig.domain example.com
# Review your ESC Environment
$ pulumi env open $E
{ "pulumiConfig": { "accountId": "111222333", "cloudflare:apiToken": "abc123abc123", "domain": "example.com" }}
e. Create a stack
To instantiate your dev
stack, run:
$ pulumi up --yes --stack dev
# wait a few seconds for the stack to be instantiated.
At this point, you have not defined any resources so you’ll have an empty stack.
Add a Zone
You will now add the Pulumi Cloudflare package and a Cloudflare Zone resource to your Pulumi program.
a. Install dependencies
$ npm install @pulumi/cloudflare
added 1 package ...
$ npm install @pulumi/cloudflare
added 1 package ...
$ echo "pulumi_cloudflare>=5.35,<6.0.0" >> requirements.txt
$ source venv/bin/activate
$ pip install -r requirements.txt
...Collecting pulumi-cloudflare...
$ go get github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare
go: downloading github.com/pulumi/pulumi-cloudflare ...
Below are Apache Maven instructions. For other Java project managers such as Gradle, see the official Maven repository
- Open your
pom.xml
file. - Add the Pulumi Cloudflare dependency inside the
<dependencies>
section.
<dependency> <groupId>com.pulumi</groupId> <artifactId>cloudflare</artifactId> <version>5.35.1</version>
</dependency>
- Run:
$ mvn clean install
...[INFO] BUILD SUCCESS...
$ dotnet add package Pulumi.Cloudflare
...info : Adding PackageReference for package 'Pulumi.Cloudflare' into project...
b. Modify the program
Replace the contents of your entrypoint file with the following:
index.js"use strict";
const pulumi = require("@pulumi/pulumi");
const cloudflare = require("@pulumi/cloudflare");
const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");
// Create a Cloudflare resource (Zone)
const zone = new cloudflare.Zone("my-zone", { zone: domain, accountId: accountId, plan: "free", jumpStart: true,
});
// Export the zone IDexports.zoneId = zone.id;
index.tsimport * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";
const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain")
// Create a Cloudflare resource (Zone)
const zone = new cloudflare.Zone("my-zone", { zone: domain, accountId: accountId, plan: "free", jumpStart: true,
});
// Export the zone ID
export const zoneId = zone.id;
__main__.pyimport pulumiimport pulumi_cloudflare as cloudflare
account_id = pulumi.Config().require("accountId")domain = pulumi.Config().require("domain")
# Create a Cloudflare resource (Zone)zone = cloudflare.Zone("my-zone", zone=domain, account_id=account_id, plan="free", jump_start=True)
# Export the zone IDpulumi.export("zoneId", zone.id)
main.gopackage main
import ( "github.com/pulumi/pulumi/sdk/v3/go/pulumi" cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare"
)
func main() { pulumi.Run(func(ctx *pulumi.Context) error { domain, _ := ctx.GetConfig("domain")
// Create a Cloudflare resource (Zone) zone, err := cloudflare.NewZone(ctx, "my-zone", &cloudflare.ZoneArgs{ Zone: pulumi.String(domain), Plan: pulumi.String("free"), JumpStart: pulumi.Bool(true), }) if err != nil { return err }
// Export the zone ID ctx.Export("zoneId", zone.ID()) return nil })
}
The entrypoint file is under the src/main/java/myproject
directory.
App.javapackage myproject;
import com.pulumi.Pulumi;
import com.pulumi.Context;
import com.pulumi.cloudflare.ZoneArgs;
import com.pulumi.cloudflare.Zone;
public class App { public static void main(String[] args) { Pulumi.run(ctx -> { var config = ctx.config();
String accountId = config.require("accountId"); String domain = config.require("domain");
var zone = new Zone("my-zone", ZoneArgs.builder() .zone(domain) .accountId(accountId) .plan("free") .jumpStart(true) .build());
ctx.export("zoneId", zone.id()); }); }
}
Program.csusing System.Threading.Tasks;
using Pulumi;
using Pulumi.Cloudflare;
class Program
{ static Task<int> Main() => Deployment.RunAsync<MyStack>();
class MyStack : Stack { public MyStack() { var config = new Pulumi.Config(); var accountId = config.Require("accountId"); var domain = config.Require("domain");
var zone = new Zone("my-zone", new ZoneArgs { ZoneName = domain, AccountId = accountId, Plan = "free", JumpStart = true });
this.ZoneId = zone.Id; }
[Output] public Output<string> ZoneId { get; set; } }
}
Pulumi.dev.yamlenvironment: - my-dev-env
resources: myZone: type: cloudflare:Zone properties: zone: ${domain} accountId: ${accountId} plan: "free" jumpStart: true
outputs: zoneId: ${myZone.id}
c. Apply the changes
$ pulumi up --yes --stack dev
# wait a few seconds while the changes take effect
d. (Optional) Review the zone
Review the value of zoneId
to confirm the Zone creation.
$ pulumi stack output zoneId
d8fcb6d731fe1c2d75e2e8d6ad63fad5
Update your nameservers
Once you have added a domain to Cloudflare, that domain will receive two assigned authoritative nameservers.
a. Update the program
Towards the end of your entrypoint file, below the zoneId
variable, add the following:
index.jsexports.nameservers = zone.nameServers;exports.status = zone.status;
index.tsexport const nameservers = zone.nameServers;
export const status = zone.status;
__main__.pypulumi.export('nameservers', zone.name_servers)pulumi.export('status', zone.status)
main.goctx.Export("nameservers", zone.NameServers)ctx.Export("status", zone.Status)
App.javactx.export("nameservers", zone.nameServers());ctx.export("status", zone.status());
- Add
using System.Collections.Immutable;
at the top of yourProgram.cs
file. - Below
this.ZoneId = zone.Id;
, add:
Program.csthis.Nameservers = zone.NameServers;
this.Status = zone.Status;
- Below
public Output<string> ZoneId { get; set; }
, add:
Program.cspublic Output<ImmutableArray<string>> Nameservers { get; set; }
public Output<string> Status { get; set; }
Pulumi.dev.yamlnameservers: ${exampleZone.nameServers}
status: ${exampleZone.status}
b. Apply the changes
$ pulumi up --yes --stack dev
c. Obtain the nameservers
Review the value of nameservers
to retrieve the assigned nameservers:
$ pulumi stack output --stack dev
d. Update your registrar
Update the nameservers at your registrar to activate Cloudflare services for your domain. Instructions are registrar-specific. You may be able to find guidance under this consolidated list of common registrars.
e. Check your domain status
Once successfully registered, your domain status
will change to active
.
$ pulumi stack output
Add a DNS record
You will now add a DNS record to your domain.
a. Modify your program
Below is the final version of how your Pulumi program entrypoint file should look. Replace the contents of your entrypoint file with the following:
index.js"use strict";
const pulumi = require("@pulumi/pulumi");
const cloudflare = require("@pulumi/cloudflare");
const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");
// Create a Cloudflare resource (Zone)
const zone = new cloudflare.Zone("my-zone", { zone: domain, accountId: accountId, plan: "free", jumpStart: true,
});
// Export the zone IDexports.zoneId = zone.id;exports.nameservers = zone.nameServers;exports.status = zone.status;
const record = new cloudflare.Record("my-record", { zoneId: zone.id, name: domain, value: "192.0.2.1", type: "A", proxied: true,
});
index.tsimport * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";
const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain")
// Create a Cloudflare resource (Zone)
const zone = new cloudflare.Zone("my-zone", { zone: domain, accountId: accountId, plan: "free", // Choose the desired plan, e.g., "free", "pro", "business", etc. jumpStart: true,
});
// Export the zone ID
export const zoneId = zone.id;
// Export the Cloudflare-assigned nameservers.
export const nameservers = zone.nameServers;
// Export the status
export const status = zone.status;
// Set up a Record for your site
const record = new cloudflare.Record("my-record", { zoneId: zoneId, name: domain, value: "192.0.2.1", type: "A", proxied: true,
});
__main__.pyimport pulumiimport pulumi_cloudflare as cloudflare
account_id = pulumi.Config().require("accountId")domain = pulumi.Config().require("domain")
# Create a Cloudflare resource (Zone)zone = cloudflare.Zone("my-zone", zone=domain, account_id=account_id, plan="free", jump_start=True)
# Export the zone IDpulumi.export("zoneId", zone.id)pulumi.export('nameservers', zone.name_servers)pulumi.export('status', zone.status)
record = cloudflare.Record("my-record", zone_id=zone.id, name=domain, value="192.0.2.1", type="A", proxied=True
)
main.gopackage main
import ( cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare" "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() { pulumi.Run(func(ctx *pulumi.Context) error { domain, _ := ctx.GetConfig("domain")
// Create a Cloudflare resource (Zone) zone, err := cloudflare.NewZone(ctx, "my-zone", &cloudflare.ZoneArgs{ Zone: pulumi.String(domain), Plan: pulumi.String("free"), JumpStart: pulumi.Bool(true), }) if err != nil { return err }
// Export the zone ID ctx.Export("zoneId", zone.ID()) ctx.Export("nameservers", zone.NameServers) ctx.Export("status", zone.Status)
_, err = cloudflare.NewRecord(ctx, "my-record", &cloudflare.RecordArgs{ ZoneId: zone.ID(), Name: pulumi.String(domain), Value: pulumi.String("192.0.2.1"), Type: pulumi.String("A"), Proxied: pulumi.Bool(true), }) if err != nil { return err }
return nil })
}
App.javapackage myproject;
import com.pulumi.Pulumi;
import com.pulumi.Context;
import com.pulumi.cloudflare.ZoneArgs;
import com.pulumi.cloudflare.Zone;
import com.pulumi.cloudflare.Record;
import com.pulumi.cloudflare.RecordArgs;
public class App { public static void main(String[] args) { Pulumi.run(ctx -> { var config = ctx.config();
String accountId = config.require("accountId"); String domain = config.require("domain");
var zone = new Zone("my-zone", ZoneArgs.builder() .zone(domain) .accountId(accountId) .plan("free") .jumpStart(true) .build());
ctx.export("zoneId", zone.id()); ctx.export("nameservers", zone.nameServers()); ctx.export("status", zone.status());
new Record("my-record", RecordArgs.builder() .zoneId(zone.id()) .name(domain) .value("192.0.2.1") .type("A") .proxied(true) .build()); }); }
}
Program.csusing System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Cloudflare;
class Program
{ static Task<int> Main() => Deployment.RunAsync<MyStack>();
class MyStack : Stack { public MyStack() { var config = new Pulumi.Config(); var accountId = config.Require("accountId"); var domain = config.Require("domain");
var zone = new Zone("my-zone", new ZoneArgs { ZoneName = domain, AccountId = accountId, Plan = "free", JumpStart = true });
this.ZoneId = zone.Id; this.Nameservers = zone.NameServers; this.Status = zone.Status;
new Record("my-record", new RecordArgs { ZoneId = zone.Id, Name = domain, Value = "192.0.2.1", Type = "A", Proxied = true });
}
[Output] public Output<string> ZoneId { get; set; } public Output<ImmutableArray<string>> Nameservers { get; set; } public Output<string> Status { get; set; } }
}
Pulumi.dev.yamlenvironment: - my-dev-env
resources: myZone: type: cloudflare:Zone properties: zone: ${domain} accountId: ${accountId} plan: "free" jumpStart: true
myRecord: type: cloudflare:Record properties: zoneId: ${myZone.id} name: ${domain} value: 192.0.2.1 type: A proxied: true
outputs: zoneId: ${myZone.id} nameservers: ${exampleZone.nameServers} status: ${exampleZone.status}
b. Apply the changes
$ pulumi up --yes --stack dev
(Optional) Verify your setup
You will run two nslookup
commands against the Cloudflare-assigned nameservers.
To test your site, run:
$ DOMAIN=$(pulumi config get domain)
$ NS1=$(pulumi stack output nameservers | jq '.[0]' -r)
$ NS2=$(pulumi stack output nameservers | jq '.[1]' -r)
$ nslookup $DOMAIN $NS1
$ nslookup $DOMAIN $NS2
For .NET use Nameservers
as the Output.
Confirm your response returns the IP address(es) for your site.
Clean up
Next steps
You have incrementally defined Cloudflare resources needed to add a site to Cloudflare. After each new resource, you apply the changes to your dev
stack via the pulumi up
command. You declare the resources in your programming language of choice and let Pulumi handle the rest.
Follow the Hello World tutorial to deploy a serverless app with Pulumi.