> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Build and deploy a FastEdge CDN application

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

FastEdge CDN applications run inside a CDN resource's request pipeline and can inspect or modify requests and responses as they pass through the CDN.

Complete the [Rust (CDN / Proxy-Wasm)](/fastedge/getting-started/setup-rust-cdn) setup before proceeding. Once deployed, attach the application to a CDN resource to process live traffic — that step is in [CDN applications](/fastedge/getting-started/integrate-cdn-with-fastedge).

## Write a handler

A CDN application consists of two parts: a root context that registers the filter factory, and a filter that implements the callbacks. Replace `src/lib.rs` with:

```rust theme={null}
use proxy_wasm::traits::*;
use proxy_wasm::types::*;

proxy_wasm::main! {{
    proxy_wasm::set_log_level(LogLevel::Info);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(Root)
    });
}}

struct Root;
impl Context for Root {}
impl RootContext for Root {
    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(Filter))
    }
    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

struct Filter;
impl Context for Filter {}
impl HttpContext for Filter {
    fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        self.add_http_request_header("x-fastedge", "cdn");
        Action::Continue
    }
}
```

`Root` registers a new `Filter` for each incoming request via `create_http_context`. `on_http_request_headers` runs when the CDN receives request headers — this example adds a custom `x-fastedge` header and returns `Action::Continue` to pass the request downstream unchanged. To stop the request instead, return `Action::Pause`.

## Build

Compile the handler to a WebAssembly binary. The first build downloads dependencies and takes one to two minutes.

```sh theme={null}
cargo build --release --target wasm32-wasip1
```

The binary is at `./target/wasm32-wasip1/release/my_cdn_app.wasm`. This file is uploaded to FastEdge in the next step.

## Deploy

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    1. In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **FastEdge** > **CDN Applications** and click **Create new application**.

    <Frame>
      <img src="https://mintcdn.com/gcore/MFAXqa6tFHU8UZIW/images/docs/fastedge/getting-started/get-started-cdn/cdn-apps-list.png?fit=max&auto=format&n=MFAXqa6tFHU8UZIW&q=85&s=3cfeb5768d44db2904cf1026fba3b29d" alt="CDN Applications page with Create new application button" width="1920" height="549" data-path="images/docs/fastedge/getting-started/get-started-cdn/cdn-apps-list.png" />
    </Frame>

    2. Click the **Upload binary** card.

    <Frame>
      <img src="https://mintcdn.com/gcore/MFAXqa6tFHU8UZIW/images/docs/fastedge/getting-started/get-started-cdn/cdn-apps-create-options.png?fit=max&auto=format&n=MFAXqa6tFHU8UZIW&q=85&s=55af07df8117bccfdd09c7c49cf6d44b" alt="Create application page with Upload binary card and template options" width="1920" height="843" data-path="images/docs/fastedge/getting-started/get-started-cdn/cdn-apps-create-options.png" />
    </Frame>

    3. Select the `.wasm` file produced in the Build step.
    4. Enter a **Name** for the application.
    5. Click **Save and deploy**.

    <p>The application is now available in the CDN Applications list. To activate it, attach it to a CDN resource — the full walkthrough is in [CDN applications](/fastedge/getting-started/integrate-cdn-with-fastedge).</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Deploying requires two API calls: upload the binary to get its ID, then create the CDN application. An [API token](/account-settings/api-tokens) is required.</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    ```

    <Warning>Do not commit API keys to source control.</Warning>

    ### Upload the binary

    ```bash theme={null}
    curl -sX POST 'https://api.gcore.com/fastedge/v1/binaries/raw' \
      -H "Authorization: APIKey $GCORE_API_KEY" \
      -H 'Content-Type: application/octet-stream' \
      --data-binary "@./target/wasm32-wasip1/release/my_cdn_app.wasm"
    ```

    <p>The response contains the binary ID:</p>

    ```json theme={null}
    {"id": 4695, "api_type": "proxy-wasm", "checksum": "c083e2b6...", "source": 1, "status": 1}
    ```

    ### Create the application

    ```bash theme={null}
    export BINARY_ID=4695

    curl -sX POST 'https://api.gcore.com/fastedge/v1/apps' \
      -H "Authorization: APIKey $GCORE_API_KEY" \
      -H 'Content-Type: application/json' \
      -d "{\"name\": \"my-cdn-app\", \"binary\": $BINARY_ID, \"status\": 1}"
    ```

    <p>The response contains the application ID:</p>

    ```json theme={null}
    {"id": 2553, "name": "my-cdn-app", "binary": 4695, "api_type": "proxy-wasm", "plan": "Free", "plan_id": 30, "status": 1}
    ```

    <p>To activate the application, attach it to a CDN resource. Attachment steps — including the CDN API call — are in [CDN applications](/fastedge/getting-started/integrate-cdn-with-fastedge).</p>
  </MethodSection>
</MethodSwitch>
