---
title: Firewall Terraform Configuration
description: Learn how to create scalable firewall configurations with Terraform
url: /kb/guide/firewall-terraform-configuration
canonical_url: "https://vercel.com/kb/guide/firewall-terraform-configuration"
published: 2025-11-03
last_updated: 2025-11-10
authors: DX Team
related:
  - /docs/accounts
  - /docs/rest-api
  - /docs/project-configuration/general-settings
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

In this guide, you will learn how to apply a series of firewall rules to multiple projects or teams by using [Terraform](https://registry.terraform.io/) to create configurations that are straightforward to manage and scalable.

### Prerequisites

- A [Vercel account](/docs/accounts) with access to the projects you want to manage.
  
- The Terraform CLI installed. Follow the [Install Terraform guide](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) to do this for all operating systems.
  
- A [Vercel personal token](/docs/rest-api#creating-an-access-token) to authenticate with the Terraform provider.
  
- The [Vercel Terraform Provider](https://registry.terraform.io/providers/vercel/vercel/latest) installed.
  

### Authenticate Terraform with Vercel

Create a folder for your terraform setup

```bash
mkdir terraform-firewall
cd terraform-firewall
```

Create a `.env` file or export your token:

```bash
export VERCEL_TOKEN="your-vercel-token"
```

Then, create a Terraform file in your project folder and add Vercel as a provider.

Create a file called main.tf and paste the following content:

```hcl
terraform {
  required_providers {
    vercel = {
      source = "vercel/vercel"
      version = "~> 0.3"
    }
  }
}
```

Run the following in the command line to initialize the project using `main.tf`:

```bash
terraform init
```

### Import your existing projects

If your Vercel projects already exist, import them into Terraform state:

```bash
terraform import vercel_project.PROJECT_1 prj_abc123
terraform import vercel_project.PROJECT_2 prj_def456
```

Where `prj_abc123` and `prj_def456` are the Vercel [project IDs](/docs/project-configuration/general-settings#project-id).

This links your Terraform code to existing Vercel projects.

### Define your firewall rules as variables

Your configuration will include the following rules:

- Suspicious user agents — Blocks known bots/crawlers.
  
- AI bots — Detects requests from AI services like GPTBot, Claude, etc.
  
- OFAC countries — Blocks traffic from sanctioned regions.
  
- WordPress URLs — Blocks scanners looking for common WordPress endpoints.
  
- Rate limiting — Limits API request frequency (per IP or JA4 fingerprint).
  

Define them in a `vercel_firewall.tf` file as follows:

- **Suspicious user agents**
  
  ```json
  variable "suspicious_user_agent_conditions" {
    description = "Conditions to challenge requests with suspicious user agents."
    type = list(object({
      type  = string
      op    = string
      value = string
    }))
    default = [
      {
        type  = "user_agent"
        op    = "ex"
        value = "01h4x.com|360Spider|404checker|404enemy|80legs|ADmantX|AIBOT|ALittle Client|ASPSeek|Abonti|Aboundex|Aboundexbot|Acunetix|AdsTxtCrawlerTP|AfD-Verbotsverfahren|AhrefsBot|AiHitBot|Aipbot|Alexibot|AllSubmitter|Alligator|AlphaBot|Anarchie|Anarchy|Anarchy99|Ankit|Anthill|Apexoo|Aspiegel|Asterias|Atomseobot|Attach|AwarioBot|AwarioRssBot|AwarioSmartBot|BBBike|BDCbot|BDFetch|BLEXBot|BackDoorBot|BackStreet|BackWeb|Backlink-Ceck|BacklinkCrawler|BacklinksExtendedBot|Badass|Bandit|Barkrowler|BatchFTP|Battleztar Bazinga|BetaBot|Bigfoot|Bitacle|BlackWidow|Black Hole|Blackboard|Blow|BlowFish|Boardreader|Bolt|BotALot|Brandprotect|Brandwatch|Buck|Buddy|BuiltBotTough|BuiltWith|Bullseye|BunnySlippers|BuzzSumo|Bytespider|CATExplorador|CCBot|CODE87|CSHttp|Calculon|CazoodleBot|Cegbfeieh|CensysInspect|ChatGPT-User|CheTeam|CheeseBot|CherryPicker|ChinaClaw|Chlooe|Citoid|Claritybot|ClaudeBot|Cliqzbot|Cloud mapping|Cocolyzebot|Cogentbot|Collector|Copier|CopyRightCheck|Copyscape|Cosmos|Craftbot|Crawling at Home Project|CrazyWebCrawler|Crescent|CrunchBot|Curious|Custo|CyotekWebCopy|DBLBot|DIIbot|DSearch|DTS Agent|DataCha0s|DatabaseDriverMysqli|Demon|Deusu|Devil|Digincore|DigitalPebble|Dirbuster|Disco|Discobot|Discoverybot|Dispatch|DittoSpyder|DnBCrawler-Analytics|DnyzBot|DomCopBot|DomainAppender|DomainCrawler|DomainSigmaCrawler|DomainStatsBot|Domains Project|Dotbot|Download Wonder|Dragonfly|Drip|ECCP/1.0|EMail Siphon|EMail Wolf|EasyDL|Ebingbong|Ecxi|EirGrabber|EroCrawler|Evil|Exabot|Express WebPictures|ExtLinksBot|Extractor|ExtractorPro|Extreme Picture Finder|EyeNetIE|Ezooms|FDM|FHscan|FacebookBot|FemtosearchBot|Fimap|Firefox/7.0|FlashGet|Flunky|Foobot|Freeuploader|FrontPage|Fuzz|FyberSpider|Fyrebot|G-i-g-a-b-o-t|GPTBot|GT::WWW|GalaxyBot|Genieo|GermCrawler|GetRight|GetWeb|Getintent|Gigabot|Go!Zilla|Go-Ahead-Got-It|GoZilla|Gotit|GrabNet|Grabber|Grafula|GrapeFX|GrapeshotCrawler|GridBot|HEADMasterSEO|HMView|HTMLparser|HTTP::Lite|HTTrack|Haansoft|HaosouSpider|Harvest|Havij|Heritrix|Hloader|HonoluluBot|Humanlinks|HybridBot|IDBTE4M|IDBot|IRLbot|Iblog|Id-search|IlseBot|Image Fetch|Image Sucker|ImagesiftBot|IndeedBot|Indy Library|InfoNaviRobot|InfoTekies|Information Security Team InfraSec Scanner|InfraSec Scanner|Intelliseek|InterGET|InternetMeasurement|InternetSeer|Internet Ninja|Iria|Iskanie|IstellaBot|JOC Web Spider|JamesBOT|Jbrofuzz|JennyBot|JetCar|Jetty|JikeSpider|Joomla|Jorgee|JustView|Jyxobot|Kenjin Spider|Keybot Translation-Search-Machine|Keyword Density|Kinza|Kozmosbot|LNSpiderguy|LWP::Simple|Lanshanbot|Larbin|Leap|LeechFTP|LeechGet|LexiBot|Lftp|LibWeb|Libwhisker|LieBaoFast|Lightspeedsystems|Likse|LinkScan|LinkWalker|Linkbot|LinkextractorPro|LinkpadBot|LinksManager|LinqiaMetadataDownloaderBot|LinqiaRSSBot|LinqiaScrapeBot|Lipperhey|Lipperhey Spider|Litemage_walker|Lmspider|Ltx71|MFC_Tear_Sample|MIDown tool|MIIxpc|MJ12bot|MQQBrowser|MSFrontPage|MSIECrawler|MTRobot|Mag-Net|Magnet|Mail.RU_Bot|Majestic-SEO|Majestic12|Majestic SEO|MarkMonitor|MarkWatch|Mass Downloader|Masscan|Mata Hari|MauiBot|Mb2345Browser|MeanPath Bot|Meanpathbot|Mediatoolkitbot|MegaIndex.ru|Metauri|MicroMessenger|Microsoft Data Access|Microsoft URL Control|Minefield|Mister PiX|Moblie Safari|Mojeek|Mojolicious|MolokaiBot|Morfeus Fucking Scanner|Mozlila|Mr.4x3|Msrabot|Musobot|NICErsPRO|NPbot|Name Intelligence|Nameprotect|Navroad|NearSite|Needle|Nessus|NetAnts|NetLyzer|NetMechanic|NetSpider|NetZIP|Net Vampire|Netcraft|Nettrack|Netvibes|NextGenSearchBot|Nibbler|Niki-bot|Nikto|NimbleCrawler|Nimbostratus|Ninja|Nmap|Nuclei|Nutch|Octopus|Offline Explorer|Offline Navigator|OnCrawl|OpenLinkProfiler|OpenVAS|Openfind|Openvas|OrangeBot|OrangeSpider|OutclicksBot|OutfoxBot|PECL::HTTP|PHPCrawl|POE-Component-Client-HTTP|PageAnalyzer|PageGrabber|PageScorer|PageThing.com|Page Analyzer|Pandalytics|Panscient|Papa Foto|Pavuk|PeoplePal|Petalbot|Pi-Monster|Picscout|Picsearch|PictureFinder|Piepmatz|Pimonster|Pixray|PleaseCrawl|Pockey|ProPowerBot|ProWebWalker|Probethenet|Proximic|Psbot|Pu_iN|Pump|PxBroker|PyCurl|QueryN Metasearch|Quick-Crawler|RSSingBot|Rainbot|RankActive|RankActiveLinkBot|RankFlex|RankingBot|RankingBot2|Rankivabot|RankurBot|Re-re|ReGet|RealDownload|Reaper|RebelMouse|Recorder|RedesScrapy|RepoMonkey|Ripper|RocketCrawler|Rogerbot|SBIder|SEOkicks|SEOkicks-Robot|SEOlyt|SEOlyticsCrawler|SEOprofiler|SEOstats|SISTRIX|SMTBot|SalesIntelligent|ScanAlert|Scanbot|ScoutJet|Scrapy|Screaming|ScreenerBot|ScrepyBot|Searchestate|SearchmetricsBot|Seekport|SeekportBot|SemanticJuice|Semrush|SemrushBot|SentiBot|SenutoBot|SeoSiteCheckup|SeobilityBot|Seomoz|Shodan|Siphon|SiteCheckerBotCrawler|SiteExplorer|SiteLockSpider|SiteSnagger|SiteSucker|Site Sucker|Sitebeam|Siteimprove|Sitevigil|SlySearch|SmartDownload|Snake|Snapbot|Snoopy|SocialRankIOBot|Sociscraper|Sogou web spider|Sosospider|Sottopop|SpaceBison|Spammen|SpankBot|Spanner|Spbot|Spider_Bot|Spider_Bot/3.0|Spinn3r|SputnikBot|Sqlmap|Sqlworm|Sqworm|Steeler|Stripper|Sucker|Sucuri|SuperBot|SuperHTTP|Surfbot|SurveyBot|Suzuran|Swiftbot|Szukacz|T0PHackTeam|T8Abot|Teleport|TeleportPro|Telesoft|Telesphoreo|Telesphorep|TheNomad|The Intraformant|Thumbor|TightTwatBot|TinyTestBot|Titan|Toata|Toweyabot|Tracemyfile|Trendiction|Trendictionbot|True_Robot|Turingos|Turnitin|TurnitinBot|TwengaBot|Twice|Typhoeus|URLy.Warning|URLy Warning|UnisterBot|Upflow|V-BOT|VB Project|VCI|Vacuum|Vagabondo|VelenPublicWebCrawler|VeriCiteCrawler|VidibleScraper|Virusdie|VoidEYE|Voil|Voltron|WASALive-Bot|WBSearchBot|WEBDAV|WISENutbot|WPScan|WWW-Collector-E|WWW-Mechanize|WWW::Mechanize|WWWOFFLE|Wallpapers|Wallpapers/3.0|WallpapersHD|WeSEE|WebAuto|WebBandit|WebCollage|WebCopier|WebEnhancer|WebFetch|WebFuck|WebGo IS|WebImageCollector|WebLeacher|WebPix|WebReaper|WebSauger|WebStripper|WebSucker|WebWhacker|WebZIP|Web Auto|Web Collage|Web Enhancer|Web Fetch|Web Fuck|Web Pix|Web Sauger|Web Sucker|Webalta|WebmasterWorldForumBot|Webshag|WebsiteExtractor|WebsiteQuester|Website Quester|Webster|Whack|Whacker|Whatweb|Who.is Bot|Widow|WinHTTrack|WiseGuys Robot|Wonderbot|Woobot|Wotbox|Wprecon|Xaldon WebSpider|Xaldon_WebSpider|Xenu|YaK|YoudaoBot|Zade|Zauba|Zermelo|Zeus|Zitebot|ZmEu|ZoomBot|ZoominfoBot|ZumBot|ZyBorg|adscanner|anthropic-ai|archive.org_bot|arquivo-web-crawler|arquivo.pt|autoemailspider|awario.com|backlink-check|cah.io.community|check1.exe|clark-crawler|coccocbot|cognitiveseo|cohere-ai|com.plumanalytics|crawl.sogou.com|crawler.feedback|crawler4j|dataforseo.com|dataforseobot|demandbase-bot|domainsproject.org|eCatch|evc-batch|facebookscraper|gopher|heritrix|imagesift.com|instabid|internetVista monitor|ips-agent|isitwp.com|iubenda-radar|linkdexbot|linkfluence|lwp-request|lwp-trivial|magpie-crawler|meanpathbot|mediawords|muhstik-scan|netEstate NE Crawler|oBot|omgili|openai|openai.com|page scorer|pcBrowser|plumanalytics|polaris version|probe-image-size|ripz|s1z.ru|satoristudio.net|scalaj-http|scan.lol|seobility|seocompany.store|seoscanners|seostar|serpstatbot|sexsearcher|sitechecker.pro|siteripz|sogouspider|sp_auditbot|spyfu|sysscan|tAkeOut|trendiction.com|trendiction.de|ubermetrics-technologies.com|voyagerx.com|webgains-bot|webmeup-crawler|webpros.com|webprosbot|x09Mozilla|x22Mozilla|xpymep1.exe|zauba.io|zgrab"
      }
    ]
  }
  ```
  
- **AI bots**
  
  ```json
  variable "ai_bots" {
    description = "Detects common AI Bot user agents."
    type = list(object({
      type  = string
      op    = string
      value = string
    }))
    default = [
      {
        type  = "user_agent"
        op    = "ex"
        value = "AI2Bot|Ai2Bot-Dolma|Amazonbot|Applebot|Applebot-Extended|Bytespider|CCBot|ChatGPT-User|Claude-Web|ClaudeBot|Diffbot|FacebookBot|FriendlyCrawler|GPTBot|Google-Extended|GoogleOther|GoogleOther-Image|GoogleOther-Video|ICC-Crawler|ImagesiftBot|Meta-ExternalAgent|Meta-ExternalFetcher|OAI-SearchBot|PerplexityBot|PetalBot|Scrapy|Timpibot|VelenPublicWebCrawler|Webzio-Extended|YouBot|anthropic-ai|cohere-ai|facebookexternalhit|img2dataset|omgili|omgilibot"
      }
    ]
  }
  ```
  
- **OFAC countries**
  
  ```json
  variable "ofac_countries" {
    description = "Detects requests from OFAC sanctioned countries (Cuba, Iran, North Korea, Syria, Russia)."
    type = list(object({
      type   = string
      op     = string
      values = list(string)
    }))
    default = [
      {
        type   = "geo_country"
        op     = "inc"
        values = ["CU", "IR", "KP", "SY", "RU"]
      }
    ]
  }
  ```
  
- **WordPress URLs**
  
  ```json
  variable "wordpress_urls" {
    description = "Detects requests to WordPress URLs."
    type = list(object({
      type  = string
      op    = string
      value = string
    }))
    default = [
      {
        type  = "path"
        op    = "ex"
        value = "/(wp-admin|wp-login\\.php|xmlrpc\\.php|wp-content|wp-includes|wp-signup\\.php|wp-activate\\.php|register\\.php|wp-register\\.php)"
      }
    ]
  }
  ```
  
- **Rate limiting**
  
  ```json
  variable "rate_limit_condition" {
    description = "Rate limit API requests."
    type = object({
      conditions = list(object({
        type  = string
        op    = string
        value = string
      }))
    })
    default = {
      conditions = [
        {
          type  = "path"
          op    = "pre"
          value = "/api"
        }
      ]
    }
  }
  
  variable "rate_limit_action" {
    description = "Rate limit API requests."
    type = object({
      action = string
      rate_limit = object({
        limit  = number
        window = number
        keys   = list(string)
        algo   = string
        action = string
      })
      action_duration = string
    })
    default = {
      action = "rate_limit"
      rate_limit = {
        limit  = 100
        window = 300
        keys   = ["ip", "ja4"]
        algo   = "fixed_window"
        action = "deny"
      }
      action_duration = "5m"
    }
  }
  ```
  

These are defined once and reused across both projects.

### Configure firewall rules per project

Each project (`PROJECT_1`, `PROJECT_2`) has a `vercel_firewall_config` that applies the rules defined in your variables.

For `PROJECT_1`, connect the following rules

```json
resource "vercel_firewall_config" "project_1_fw_config" {
  project_id = vercel_project.PROJECT_1.id

  rules {
    rule {
      name        = "Suspicous User Agent - Terraform"
      description = "Challenge requests with suspicious user agents."
      condition_group = [
        {
          conditions = var.suspicious_user_agent_conditions
        }
      ]
      action = {
        action = "challenge"
      }
    }

    rule {
      name        = "Block AI Bots - Terraform"
      description = "Block requests from common AI Bot user agents."
      condition_group = [
        {
          conditions = var.ai_bots
        }
      ]
      action = {
        action = "challenge"
      }
    }

    rule {
      name        = "Block OFAC Countries - Terraform"
      description = "Block requests from OFAC sanctioned countries."
      condition_group = [
        {
          conditions = var.ofac_countries
        }
      ]
      action = {
        action = "deny"
      }
    }

    rule {
      name        = "Block WordPress URLs - Terraform"
      description = "Block requests to WordPress URLs."
      condition_group = [
        {
          conditions = var.wordpress_urls
        }
      ]
      action = {
        action = "deny"
      }
    }

    rule {
      name        = "Rate limit API"
      description = "apply ratelimit to requests under /api"
      condition_group = [{
        conditions = var.rate_limit_condition.conditions
      }]

      action = var.rate_limit_action
    }
  }
}
```

And for `PROJECT_2`, connect the following rules:

```json
resource "vercel_firewall_config" "project_2_waf_config" {
  project_id = vercel_project.PROJECT_2.id

  rules {
    rule {
      name        = "Suspicous User Agent - Terraform"
      description = "Challenge requests with suspicious user agents."
      condition_group = [
        {
          conditions = var.suspicious_user_agent_conditions
        }
      ]
      action = {
        action = "challenge"
      }
    }

    rule {
      name        = "Block AI Bots - Terraform"
      description = "Block requests from common AI Bot user agents."
      condition_group = [
        {
          conditions = var.ai_bots
        }
      ]
      action = {
        action = "challenge"
      }
    }

    rule {
      name        = "Block OFAC Countries - Terraform"
      description = "Block requests from OFAC sanctioned countries."
      condition_group = [
        {
          conditions = var.ofac_countries
        }
      ]
      action = {
        action = "deny"
      }
    }

    rule {
      name        = "Block WordPress URLs - Terraform"
      description = "Block requests to WordPress URLs."
      condition_group = [
        {
          conditions = var.wordpress_urls
        }
      ]
      action = {
        action = "deny"
      }
    }

    rule {
      name        = "Rate limit API"
      description = "apply ratelimit to requests under /api"
      condition_group = [{
        conditions = var.rate_limit_condition.conditions
      }]

      action = var.rate_limit_action
    }
  }
}
```

This structure lets you enforce a consistent policy across multiple projects.

### Initialize and Apply

Run the following from the command line:

```bash
terraform init
terraform plan
terraform apply
```

This will apply the rules defined for each project as defined for `PROJECT_1` and `PROJECT_2`. Terraform loads all `.tf` files in the current working directory, merges them, and treats them as a single configuration.

### Recommendations

- Test with `terraform plan` to preview changes before applying.
  
- Store the project IDs and sensitive values using environment variables.