# American Cloud — Complete documentation > American Cloud offers powerful compute, zero egress fees, and no lock-in. Cloud infrastructure built and operated in America. --- # Cloud compute Virtual machines and compute instances ## American Cloud & Cloudflare Tunnels ## Introduction This article explores using Cloudflare Tunnels to simplify application deployment, using a NextJS app with MongoDB as a practical example scenario. ## Key Problem Traditionally, exposing applications requires handling multiple complex tasks: - Configuring firewalls - Setting up reverse proxies - Managing DNS - Obtaining SSL certificates - Implementing access controls This creates security risks through misconfiguration. ## Benefits of Tunnels - No exposing of inbound ports needed - No reverse proxy required - No need to manage DNS records - Built-in encryption - Granular access rules - Simplified setup versus traditional networking approaches ## Implementation Steps ### Initial Setup 1. Create a Cloudflare account with Zero Trust features 2. Configure at least one domain in Cloudflare 3. Create a Cloudflared tunnel and note the authentication token 4. Update docker-compose configuration ### Docker Configuration The guide provides a complete docker-compose.yaml example with four services: - nextjs-app - mongo - mongo-express - cloudflared All containers connect via a custom bridge network with no exposed ports. ### Access Control - **Public Hostname:** Route app.mydomain.com to nextjs-app:3000 - **Restricted Hostname:** Route mongo-express.mydomain.com to mongo-express:8081 - Create Access Group restricting mongo-express to emails ending in @mydomain.com ## Advanced: Automated Deployments The article extends the setup with watchtower for automatic container updates triggered by CI/CD pipelines. When code is pushed, a GitHub Actions or GitLab CI workflow builds a new image and sends an HTTP request to watchtower, automatically rebuilding the application. ## Cloud Compute Cloud compute refers to the use of remote computing resources delivered over the internet, such as virtual machines (VMs) or containers, provided by cloud service providers. These resources can be configured and managed remotely, allowing users to run applications, store data, and perform computing tasks without having to invest in and maintain their own physical infrastructure. Cloud compute offers scalability, flexibility, and cost-effectiveness, as users can pay for only the resources they need and easily adjust their computing capacity as requirements change. ## Deploy a virtual machine 1. Log in to the American Cloud portal with a valid account. 2. In the left navigation, under **Compute**, select **Virtual machines**. 3. In the top right of the Virtual machines page, click **+ Create VM**. ![Virtual machines list with the Create VM button highlighted](/docs/images/cloud-compute/cloud-compute-01.png) 4. On the **Create virtual machine** page, fill out the **Configuration** section: ### VM name Enter a name for the VM. Lowercase letters, numbers, and hyphens only (for example, `test-vm-01`). Use a unique name so it's easy to identify the instance later. ### Region Choose the geographic region where the VM will run (for example, **US Central**). ### Package type Select a package type (for example, **Standard Custom**). The package type determines the available CPU, memory, and storage ranges shown in **Hardware Specifications**. ### Deploy from Choose what to deploy from: - **Operating system** — Deploy a standard OS image. - **Marketplace app** — Deploy a preconfigured marketplace application. For more information on marketplace apps, see the [Marketplace](/docs/marketplace) category. ### Operating system If you selected **Operating system** above, choose the OS image (for example, **Ubuntu 26.04 LTS**). ### Network Choose a network for the VM. Select **Create one for me** to have American Cloud provision a network automatically, or pick an existing VPC from the dropdown. For more information about networking options, see the [Networking](/docs/networking) category. ![Create virtual machine form showing VM name, Region, Package type, Deploy from, Operating system, and Network fields](/docs/images/cloud-compute/cloud-compute-02.png) 5. Configure the **Hardware Specifications** section: ### CPU Use the slider to set the number of vCPUs (1–12 vCPU). ### Memory Use the slider to set the amount of memory (1–128 GB). ### Root disk Use the slider to set the size of the root disk (25–10,000 GB). 6. Configure the **Options** section: ### Billing period Choose **Hourly** or **Monthly**. Monthly billing offers a discount for sustained use. ### SSH keys Select any SSH keys you want to add to the VM. Keys must be added to your account before they appear here. For more information on adding SSH keys, see [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys). ### User data / cloud-init Optionally, paste a startup script (for example, a bash script that installs nginx). The script runs on first boot and is automatically base64 encoded. ![Create virtual machine form showing Hardware Specifications sliders and Options including Billing period, SSH keys, and User data](/docs/images/cloud-compute/cloud-compute-03.png) 7. Review the estimated cost shown at the bottom of the page and click **Create VM**. > **Note:** The first VM may take up to a minute to deploy. After the VM is created, you are redirected to its details page. ## Manage a virtual machine To manage a VM, open the **Virtual machines** page from the left navigation, then click the VM's name to open its details page. The details page shows the VM's status, IP address, region, and network at the top, followed by **Hardware** and **Configuration** panels. The top right of the page has three controls: **Power**, **Manage**, and **Delete**. ### Power The **Power** menu controls the running state of the VM. - **Start** — Power on a stopped VM. - **Stop** — Power off the VM. - **Restart** — Power cycle the VM. ![VM details page with the Power menu open showing Start, Stop, and Restart](/docs/images/cloud-compute/cloud-compute-04.png) ### Manage The **Manage** menu provides actions for configuring the VM. - **Console** — Open a browser-based console to the VM. - **Scale** — Change the VM's CPU, memory, or root disk size. - **Change Hostname** — Update the VM's hostname. - **Reset Password** — Generate a new root password. Available only when the VM is in a stopped state. - **Reinstall** — Wipe the VM and reinstall the operating system. > **Note:** Reinstalling a VM destroys all data on the root disk. Take a snapshot first if you need to preserve anything. ![VM details page with the Manage menu open showing Console, Scale, Change Hostname, Reset Password, and Reinstall](/docs/images/cloud-compute/cloud-compute-05.png) ### Delete The **Delete** button in the top right permanently removes the VM and its root disk. This action cannot be undone. ### Hardware and Configuration The **Hardware** panel shows the VM's CPU, memory, root disk, and package type. The **Configuration** panel shows the image, billing period, IP address, network, region, and creation time. To change hardware (CPU, memory, root disk), use **Manage → Scale**. ### Metrics The **Metrics** section shows CPU, memory, network, and disk graphs. Metrics become available after the VM has been running for at least one hour. ### Root disk snapshots Use the **+ Take Snapshot** button to capture a point-in-time copy of the root disk. Snapshots can be used to restore the VM or to create a new VM from the same state. Use a clear naming convention so snapshots are easy to identify later. For more information on SSH keys, see [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys). For firewalls and port forwarding, see the [Networking](/docs/networking) category. ## Instance creation with root SSH permitted To enable SSH access to a new virtual machine, add a public key to your American Cloud account, then select that key when you create the VM. ## Add an SSH key to your account 1. In the left navigation, under **Account**, select **SSH keys**. 2. In the top right, click **+ Add Key**. ![SSH keys page in the portal with the Add Key button highlighted](/docs/images/cloud-compute/instance-creation-with-root-ssh-permitted-01.png) 3. In the **Add SSH Key** dialog, enter a **Name** for the key (for example, `test-key`). 4. Do one of the following: - Paste your existing public key into the **Public key** field, then click **Add Key**. - Leave the **Public key** field empty and click **Generate Key** to have American Cloud generate a new key pair for you. ![Add SSH Key dialog with Name, Public key, and Generate Key button](/docs/images/cloud-compute/instance-creation-with-root-ssh-permitted-02.png) > **Note:** If you click **Generate Key**, download and store the private key immediately. It is shown only once. ## Attach the key when creating a VM 1. Start a new VM as described in [Cloud Compute](/docs/cloud-compute/cloud-compute). 2. In the **Options** section of the Create virtual machine page, under **SSH keys**, check the box next to the key you want to add. ![Options section of the Create VM page showing the SSH keys field](/docs/images/cloud-compute/instance-creation-with-root-ssh-permitted-03.png) 3. Click **Create VM**. ## Connect to the VM Once the VM is running, copy its public IP from the details page and connect: ```bash ssh root@ ``` Use the private key that pairs with the public key you attached. If you generated the key in the portal, use the file you downloaded. ## Managing SSH keys ## About SSH Keys SSH key, or Secure Shell key, is a cryptographic key pair used for securely authenticating and encrypting communication between two entities in a Secure Shell (SSH) protocol-based system, such as remote access to a server or a Git repository. SSH is a widely used protocol for securely connecting to and managing remote servers over a network. An SSH key pair consists of two keys: a private key and a public key. The private key is kept secret and is known only to the owner, while the public key is shared with other parties. When a client initiates an SSH connection to a server, the server requests the client to authenticate using a key pair. The client uses its private key to generate a digital signature, which is sent to the server along with the public key. The server then uses the public key to verify the digital signature, and if it matches, the client is granted access. ## RSA vs ED2519 RSA and Ed25519 are two different types of cryptographic key pairs used in SSH for secure communication and authentication. Here are the key differences between RSA and Ed25519 key pairs: ### Algorithm RSA (Rivest-Shamir-Adleman) is a widely used asymmetric encryption algorithm, while Ed25519 is a newer elliptic curve cryptography (ECC) algorithm. ### Key Size RSA key pairs typically have larger key sizes, such as 2048 bits or 4096 bits, while Ed25519 key pairs have a fixed key size of 256 bits. This means that RSA keys are generally larger and require more computational resources for key generation, encryption, and decryption compared to Ed25519 keys. ### Security Both RSA and Ed25519 are considered secure for most purposes. However, Ed25519 is generally considered to provide stronger security with smaller key sizes compared to RSA, due to the use of elliptic curve cryptography, which offers higher security levels with shorter key lengths. RSA is susceptible to attacks such as factorization, while Ed25519 is designed to be resistant to various cryptographic attacks. ### Performance Ed25519 is known for its faster performance compared to RSA, as it requires less computational resources for key generation, encryption, and decryption. This makes Ed25519 more efficient for use in resource-constrained environments, such as embedded systems or high-traffic networks. ### Compatibility RSA is more widely supported and compatible with older systems and software, as it has been in use for a longer time. Ed25519, being a newer algorithm, may not be supported by all SSH implementations or older systems. However, most modern SSH clients and servers support Ed25519, and it is gaining wider adoption in recent years. ### Key Management RSA keys are typically managed using the ssh-keygen tool, which is available on most operating systems. Ed25519 keys can also be generated using ssh-keygen, but it may require a newer version of the tool that supports ECC algorithms. Additionally, RSA keys often require regular key size updates for maintaining strong security, while Ed25519 keys are fixed at 256 bits. In summary, RSA and Ed25519 are both commonly used for SSH key-based authentication, but they differ in terms of algorithm, key size, security, performance, compatibility, and key management. The choice between RSA and Ed25519 depends on the specific use case, security requirements, and compatibility considerations of the system or network being used. ## Generating SSH Keys ### Generating SSH Keys using Terminal/CMD Prompt Here are two ways to generate an SSH key for use within the American Cloud Cloud Management Platform (CMP). Generate within the terminal or cmd prompt using the following commands: ### Terminal or CMD Prompt Open a terminal or cmd prompt on your local machine. ### Run Commands Run the command to generate rsa and/or ed2519 keys - RSA ``` ssh-keygen -t rsa -b 4096 -C "your_email@example.com" ``` - Ed2519 ``` ssh-keygen -t ed25519 -C "your_email@example.com" ``` ### Generate a keypair in the portal The American Cloud portal can generate an SSH keypair for you. Use this option if you don't already have a key. 1. In the left navigation, under **Account**, select **SSH keys**. ![SSH keys page in the portal](/docs/images/cloud-compute/managing-ssh-keys-01.png) 2. In the top right, click **+ Add Key**. 3. In the **Add SSH Key** dialog, enter a **Name** for the key. 4. Leave the **Public key** field empty and click **Generate Key**. ![Add SSH Key dialog with Generate Key button](/docs/images/cloud-compute/managing-ssh-keys-02.png) 5. Download and save the private key to your local machine immediately. It is shown only once. Once saved, the new key appears in the SSH keys list and is ready to attach to a virtual machine. ## Placing pre-generated keys If you already have an SSH keypair, upload the public key to your account. 1. In the left navigation, under **Account**, select **SSH keys**. 2. In the top right, click **+ Add Key**. 3. In the **Add SSH Key** dialog, enter a **Name** for the key. 4. Paste your public key into the **Public key** field and click **Add Key**. Once added, the key appears in the SSH keys list with its fingerprint and is ready to attach to a virtual machine. ## Deleting an SSH key To remove an SSH key from your account, find the key in the SSH keys list and click **Delete** on its row. ![SSH keys page with the Delete button on a key row](/docs/images/cloud-compute/managing-ssh-keys-03.png) > **Note:** Deleting a key removes it from your account but does not remove it from any virtual machines it has already been attached to. ## Attaching a key to a virtual machine To use an SSH key on a new VM, select it in the **SSH keys** field on the Create VM page. See [Cloud Compute](/docs/cloud-compute/cloud-compute) for the full VM creation flow. --- # Kubernetes American Cloud Kubernetes Service (ACKS) ## Accessing Your Kubernetes Cluster via Public IP When deploying a Kubernetes cluster on American Cloud, it's important to understand the differences between the **API Load Balancer IP**, **Source NAT IP**, and your **Ingress Service IP**. ## Common Issue **Error Message:** `403 | ATTEMPT TO READ PROPERTY "NETWORK" ON NULL` **Cause:** This usually occurs when attempting to **port forward the cluster's API Load Balancer IP**, which is reserved for **Kubernetes API access only**. It is **not intended** for use with services deployed inside the cluster. ## Understanding Public IPs in Your Deployment **API Load Balancer IP** `0.0.0.0` – Used only for Kubernetes API access. Shown in the cluster card in the dashboard **Source NAT IP** `0.0.0.0` -Used for outbound traffic from the cluster. Found in the network card > Public IP Addresses **Ingress IP** `0.0.0.1` – For routing public traffic to your services (via nginx, istio, etc.) Retrieved via `kubectl` only ⚠️ *Note:* The **Ingress IP is not shown in the dashboard**. You must use Kubernetes commands to retrieve it. ## Retrieving the Correct Ingress IP Depending on the ingress controller you are using, run one of the following commands: ### If using **NGINX**: ``` bash kubectl get svc -n ingress-nginx ``` ### If using **Istio**: ``` bash kubectl get svc istio-ingressgateway -n istio-system ``` Look for the value under the `EXTERNAL-IP` column — this is the IP you should use to expose your services externally. ## Best Practices - Do **not** attempt to port forward the API Load Balancer or Source NAT IP. - Retrieve your Ingress IP using `kubectl`, since this IP is not currently displayed in the dashboard. - Ensure your ingress service is of type `LoadBalancer`. - Avoid manually adjusting firewall/network rules in the dashboard — these should be controlled via Kubernetes. - Consider using DNS to point to your ingress IP for stable access. ## Example From the dashboard: - **Cluster Name**: `my-k8s-cluster` - **API Load Balancer IP**: `0.0.0.0` - **Source NAT IP**: `0.0.0.0` - **Allocated IPs**: - `0.0.0.0` — Source NAT - `0.0.0.1` — Likely ingress service IP (with FW rules defined) From `kubectl`: ``` bash kubectl get svc istio-ingressgateway -n istio-system ``` Example output: ``` pgsql NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) istio-ingressgateway LoadBalancer 10.96.0.1 0.0.0.1 80:31380/TCP ``` ✅ Use `0.0.0.1` to access your workloads via the ingress controller. ## Kubernetes — getting started Kubernetes (often abbreviated as **K8s**) is an open-source container orchestration platform for automating the deployment, scaling, and management of containerized applications. American Cloud Kubernetes Service (**ACKS**) is American Cloud's fully-managed Kubernetes offering — you create a cluster, the platform provisions control and worker nodes for you, and you interact with it through `kubectl`. This article walks through installing `kubectl`, creating an ACKS cluster, downloading its kubeconfig, and scaling or upgrading the cluster from the portal. ## Install kubectl ### macOS ```bash brew install kubernetes-cli ``` ### Linux ```bash curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl ``` ### Windows See the [official kubectl install guide](https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/). ## Create an ACKS cluster 1. In the left navigation, under **Compute**, select **Kubernetes**. 2. In the top right of the Kubernetes page, click **+ Create Cluster**. ![Kubernetes page with the Create Cluster button highlighted](/docs/images/kubernetes/getting-started-01.png) 3. On the **Create Kubernetes cluster** page, fill in the **Configuration** section: - **Cluster name** — lowercase letters, numbers, and hyphens (for example, `my-app-k8`). - **Region** — for example, **US Central**. - **Package** — sets the size and pricing tier of each node (for example, **Scale ACKS — 4 vCPU, 8 GB memory**). - **Kubernetes version** — the version to install (for example, `1.33.1`). - **Network** *(optional)* — an existing VPC tier. Leave blank and CloudStack creates an isolated network automatically. ![Create Kubernetes cluster Configuration section](/docs/images/kubernetes/getting-started-02.png) 4. Configure the **Node Pool**: - **Control nodes** — 1–11. Three or more control nodes provide HA via an etcd quorum that tolerates a one-node failure. - **Worker nodes** — 1–32. 5. In **Options**: - **SSH keypair** — recommended; allows SSH access to cluster nodes. Add a key first under **Account → SSH keys** if you don't have one (see [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys)). - **Description** — optional. 6. Review the estimated cost at the bottom and click **Create Cluster**. ![Create Kubernetes cluster Node Pool and Options sections](/docs/images/kubernetes/getting-started-03.png) The cluster appears in the Clusters list with status **CREATING**. Provisioning takes a few minutes. ![Clusters list showing a new cluster with status CREATING](/docs/images/kubernetes/getting-started-04.png) Once status is **RUNNING**, the row populates with version, region, package, node counts, and per-node specs. ![Clusters list showing a cluster with status RUNNING](/docs/images/kubernetes/getting-started-05.png) ## Cluster detail page Click a cluster in the list to open its detail page. The page summarizes the cluster and exposes four action buttons in the top right. ![Cluster detail page with Kubeconfig, Power, Manage, and Delete actions](/docs/images/kubernetes/getting-started-06.png) Sections on the page: - **Node Pool** — control node count, worker node count, total CPU, total memory. - **Configuration** — region, IP address, Kubernetes version, package, autoscaling state, total nodes, creation time, description. - **Nodes** — each node's name, role (control/worker), state, IP, CPU, memory, and root disk. - **Load Balancer Rules** — the rules attached to the cluster's public IP (the Kubernetes API server rule, plus any rules you've added). See [Load balancer](/docs/load-balancing/load-balancer). ### Actions - **Kubeconfig** — download the cluster's kubeconfig file. - **Power** — start or stop the cluster. - **Manage** — scale, autoscale, or upgrade (see below). - **Delete** — permanently remove the cluster and its nodes. ## Download and use the kubeconfig 1. On the cluster detail page, click **Kubeconfig** to download the file (typically to your `~/Downloads` folder). 2. Point `kubectl` at it: ```bash export KUBECONFIG=~/Downloads/kube.conf ``` 3. Verify the connection: ```bash kubectl get nodes ``` You should see the control and worker nodes listed. ## Scale, autoscale, and upgrade Open the cluster's detail page and click **Manage** in the top right. Three options appear. ![Manage menu showing Scale Workers, Autoscale, and Upgrade](/docs/images/kubernetes/getting-started-07.png) ### Scale workers Change the worker node count manually. 1. Click **Manage → Scale Workers**. 2. In the **Scale Worker Nodes** dialog, set the new worker count (1–20) on the slider. 3. Click **Apply**. ![Scale Worker Nodes dialog with a slider](/docs/images/kubernetes/getting-started-08.png) ### Autoscale Click **Manage → Autoscale** to enable automatic worker scaling based on cluster load. See [Autoscaling](/docs/kubernetes/autoscaling) for details. ### Upgrade Click **Manage → Upgrade** to upgrade the cluster to a newer Kubernetes version. If you're already on the latest available version, the dialog says so. ![Upgrade Kubernetes Version dialog](/docs/images/kubernetes/getting-started-09.png) ## Related articles - [Accessing your Kubernetes cluster via public IP](/docs/kubernetes/accessing-your-kubernetes-cluster-via-public-ip) - [Scaling a Kubernetes cluster](/docs/kubernetes/scaling-a-kubernetes-cluster) - [Autoscaling](/docs/kubernetes/autoscaling) - [Renewing control plane certificates](/docs/kubernetes/renewing-control-plane-certificates) ## Renewing Kubernetes control plane certificates Kubernetes control plane certificates expire after one year by default. This guide covers how to renew them on each control plane node using `kubeadm`. - SSH access to each control plane node - `kubeadm` installed on the node - Sufficient permissions to run `sudo` commands Run these steps on **each control plane node** individually. Restarting kubelet will briefly interrupt the API server on that node. ## Check certificate expiration Before renewing, confirm which certificates are expiring: ```bash sudo kubeadm certs check-expiration ``` The output lists each certificate alongside its expiration date and the certificate authority that signed it. ## Renew all certificates ```bash sudo kubeadm certs renew all ``` This renews all certificates managed by `kubeadm`, including the API server, controller manager, scheduler, and etcd certificates. ## Restart kubelet ```bash sudo systemctl restart kubelet ``` The kubelet must be restarted to pick up the renewed certificates. ## Verify the renewal Run the expiration check again to confirm new expiry dates: ```bash sudo kubeadm certs check-expiration ``` All certificates should now show an expiration date approximately one year from today. ## Update your local kubeconfig After renewing, copy the updated admin config to your home directory: ```bash sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config ``` ## Confirm the cluster is back online ```bash kubectl get namespaces kubectl get nodes kubectl get pods -A ``` All nodes should show **Ready** and system pods should be **Running** or **Completed**. ## Scaling a Kubernetes cluster This guide explains how to add or remove worker nodes on a managed Kubernetes cluster from the American Cloud interface. ## Scale your cluster 1. Log in to the [American Cloud interface](https://app.americancloud.com). 2. Navigate to **Kubernetes** and select your Kubernetes project. 3. On the **Manage Cluster** page, click the **Scale** button (↑) in the top-right corner of the cluster header. 4. Enter the **total number of worker nodes** you want the cluster to have. The number you enter is the desired **total** worker count — not the number of nodes to add. For example, if your cluster currently shows **Size: 4** and you want one more, enter **5**. 5. Confirm the change. ## Verify the scaled cluster Once scaling completes, the **Overview** tab will reflect the updated **Size** and total CPU/RAM. You can also confirm from the command line: ```bash kubectl get nodes ``` All nodes should show a status of **Ready**. ## Contact support If you are unable to scale your cluster or need assistance, contact American Cloud support via our chat widget. --- # DNS Domain name management and configuration ## DNS management American Cloud's DNS Manager lets you create DNS zones and manage records for your domains directly from the portal. It supports the common record types: A, AAAA, CNAME, MX, TXT, NS, SOA, SRV, and CAA. ## Understanding DNS DNS attaches human-readable domain names to machine-usable IP addresses. Instead of needing to know the IP address of the website you are navigating to, you can enter [https://americancloud.com](https://americancloud.com/) for example. ## Register the domain American Cloud is not a domain registrar, but the DNS Manager works with any registrar (for example, GoDaddy, BlueHost, or HostGator). Register your domain there first, then point its name servers at American Cloud as described in [Use American Cloud's name servers](#use-american-clouds-name-servers). ## Create a DNS zone 1. In the left navigation, under **Networking**, select **DNS**. 2. In the top right of the DNS zones page, click **+ Create Zone**. ![DNS zones page in the portal with the Create Zone button](/docs/images/dns/dns-management-01.png) 3. On the **Create DNS zone** page, enter your domain in the **Domain name** field (for example, `exampledomain.com` — no `www.` prefix). 4. Click **Create Zone**. ![Create DNS zone page with Domain name field and Create Zone button](/docs/images/dns/dns-management-02.png) The new zone is created with two default NS records pointing at American Cloud's name servers. ![New DNS zone page showing default NS records](/docs/images/dns/dns-management-03.png) ## Add DNS records DNS records associate domain names with information such as a server's IP address or a mail server. American Cloud supports the following record types: - A and AAAA - CNAME - MX - TXT - NS - SOA - SRV - CAA To add a record: 1. From the DNS zones page, click the zone you want to manage. 2. In the **Records** section, click **+ Add Record**. 3. Choose the record **Type**, enter the **Name**, **TTL**, and **Value**, then save. To change or remove a record, use the **[edit]** or **[delete]** links on its row. ![DNS zone detail page showing Add Record button and edit/delete actions on each record](/docs/images/dns/dns-management-04.png) If you are migrating to American Cloud from another DNS provider, add all of the necessary records here before pointing your domain's registrar at American Cloud's name servers. ## Use American Cloud's name servers Once your records are in place, set American Cloud's name servers as the authoritative name servers for your domain. Log in to your domain registrar's control panel and set the name servers for your domain to: - `ns1.americancloud.org` - `ns2.americancloud.org` See your registrar's documentation for the exact steps. ## Delete a DNS zone To remove a zone, open it from the DNS zones page and click **[delete zone]** in the top right. > **Note:** Deleting a zone removes all of its records. If the zone is still authoritative for a live domain, queries will fail until you update the registrar. --- # Load balancing Traffic distribution and high availability ## Load balancer A load balancer distributes incoming traffic across multiple virtual machines so no single VM is overwhelmed. On American Cloud, load balancing is configured as a set of **load balancer rules** attached to a public IP — there is no separate "Load Balancer" resource. Each rule maps a public port on the IP to a private port on one or more backend VMs. ## Prerequisites Before you create a rule, you need: - At least two VMs running the same application. See [Cloud Compute](/docs/cloud-compute/cloud-compute). - A public IP allocated to the network those VMs are attached to. ## Add a load balancer rule 1. In the left navigation, under **Networking**, select **Public IPs**. ![Public IPs page in the portal](/docs/images/load-balancing/load-balancer-01.png) 2. Click the public IP you want to load-balance traffic on. 3. Scroll to the **Load Balancer Rules** section and click **+ Add Rule**. 4. In the **Add Load Balancer Rule** dialog, fill in the fields: - **Name** — a unique name for the rule (for example, `web-https`). - **Algorithm** — how traffic is distributed across backends. **Round Robin** is the default. - **Public port** — the port clients connect to on the public IP (for example, `443`). - **Private port** — the port on the backend VMs that receives the traffic (for example, `443`). - **Protocol** — `TCP` or `UDP`. 5. Click **Add Rule**. ![Add Load Balancer Rule dialog with Name, Algorithm, Public port, Private port, and Protocol fields](/docs/images/load-balancing/load-balancer-02.png) The new rule appears in the Load Balancer Rules list. ## Attach VMs to a rule A rule does nothing until you tell it which VMs to send traffic to. 1. Find the rule in the Load Balancer Rules list and click **VMs**. 2. Select the VMs that should receive traffic for this rule. 3. Save. The selected VMs show up in the **Instances** column on the rule's row. ## Manage rules Each rule row has three actions: - **Edit** — change name, algorithm, ports, or protocol. - **VMs** — change which backends receive traffic. - **Delete** — remove the rule. ![Load Balancer Rules list showing an active rule with Edit, VMs, and Delete actions](/docs/images/load-balancing/load-balancer-04.png) ## Rule state The **State** column shows the current status of each rule. A rule must be **ACTIVE** to serve traffic. ![Load Balancer Rules list with the State column showing ACTIVE](/docs/images/load-balancing/load-balancer-03.png) If a rule is not active, check that at least one VM is attached and that the protocol and ports match what the application is listening on. --- # Block storage Persistent SSD storage volumes and snapshots ## Block storage Block storage volumes are persistent disks you can attach to a virtual machine. Use them for website files, databases, media, backups, and any other data that needs to outlive a single VM. Volumes can be attached, detached, resized, and snapshotted from the portal. ## Create a volume 1. In the left navigation, under **Storage**, select **Block storage**. 2. In the top right of the Block storage page, click **+ Create Volume**. ![Block storage page with the Create Volume button highlighted](/docs/images/block-storage/block-storage-01.png) 3. On the **Create block storage** page, fill in the **Configuration** section: - **Volume name** — lowercase letters, numbers, and hyphens only (for example, `new-disk`). - **Region** — the region the volume lives in. A volume can only be attached to a VM in the same region. 4. In the **Volume size** section, use the slider to set the size (5 GB – 2,000 GB). 5. Review the estimated monthly cost at the bottom, then click **Create Volume**. ![Create block storage form with Volume name, Region, and Volume size fields](/docs/images/block-storage/block-storage-02.png) The new volume appears in the Block storage list with status **AVAILABLE**. ![Block storage list with the new volume](/docs/images/block-storage/block-storage-03.png) ## Volume detail page Click a volume in the list to open its detail page. The page shows two panels and three actions in the top right. ![Volume detail page with Attach, Resize, and Delete buttons](/docs/images/block-storage/block-storage-04.png) - **Storage** — size and region. - **Configuration** — attached VM (or `Not attached`), region, and creation time. - **Attach** — attach the volume to a VM in the same region. - **Resize** — increase the volume's size. - **Delete** — permanently destroy the volume. ## Attach to a VM 1. On the volume detail page, click **Attach** in the top right. 2. In the **Attach Volume** dialog, select a VM from the **Virtual machine** dropdown. Only VMs in the same region as the volume appear. 3. Click **Attach**. ![Attach Volume dialog with the Virtual machine dropdown](/docs/images/block-storage/block-storage-05.png) After the volume is attached, the **Attached VM** field on the Configuration panel shows the VM's name, and the **Attached VM** column on the list page is populated. Once attached, log in to the VM and create a file system, mount the volume, and (optionally) add it to `/etc/fstab` so it mounts automatically at boot. The new device appears at a path such as `/dev/sdb` or `/dev/vdb`. ## Detach from a VM To detach, open the volume's detail page and click **Detach** in the top right (this button replaces **Attach** when the volume is in use). Unmount the volume on the VM before detaching to avoid data loss. ## Resize a volume 1. Open the volume's detail page and click **Resize** in the top right. 2. Choose the new size (must be larger than the current size; volumes cannot be shrunk). 3. Confirm. You may need to resize the file system inside the VM after the volume is grown. ## Snapshot a volume The volume detail page has a **Snapshots** section with a **+ Create Snapshot** button. A snapshot is a point-in-time copy of the volume that you can use to restore data or create a new volume. For more on snapshots, see [Snapshots](/docs/block-storage/snapshots). ## Delete a volume On the volume's detail page, click **Delete** in the top right. Detach the volume from any VM first. > **Note:** Deleting a volume permanently destroys all of its data. The action cannot be undone. --- # Object storage S3-compatible object storage (A2 Storage) ## A2 object storage A2 is American Cloud's S3-compatible object storage. You create a **storage unit**, then organize data into **buckets** and optional **folders** inside each bucket. Everything is reachable through the S3 API or directly in the portal. ## About object storage Object storage stores data as discrete objects, each with a unique identifier, rather than in a hierarchical file system. Each object can be any size or format — documents, images, videos, backups, or other unstructured data. Object storage is highly scalable, durable, and accessible over the network using standard S3 APIs. Key features: - **Scalability** — capacity grows without disrupting existing objects. - **Durability** — multiple copies are kept across nodes to protect against hardware failures. - **S3 API access** — use any S3-compatible tool (such as `s3cmd`, AWS CLI, or rclone) against the A2 endpoint. - **Metadata** — attach key/value pairs to objects for indexing or app-specific information. ## Create a storage unit 1. In the left navigation, under **Storage**, select **Object storage**. 2. In the top right of the Object storage page, click **+ Create Unit**. ![Object storage page with the Create Unit button highlighted](/docs/images/object-storage/a2-object-storage-01.png) 3. On the **Create object storage** page, enter a **Name**. Alphanumeric characters only (`a-z`, `A-Z`, `0-9`), max 100 characters. 4. Click **Create Storage Unit**. ![Create object storage form with Name field](/docs/images/object-storage/a2-object-storage-02.png) The new unit appears in the storage units list. Its full name is `$` (for example, `romanmc87085552556$teststorage`). By default the unit has no usage limit and supports up to 10,000 buckets. ![Object storage list showing the new storage unit](/docs/images/object-storage/a2-object-storage-03.png) ## Storage unit overview Click a storage unit in the list to open its detail page. The page is divided into three panels. ![Storage unit detail page showing Storage, S3 Access, and Buckets panels](/docs/images/object-storage/a2-object-storage-04.png) ### Storage Shows current usage: **Used**, **Limit**, **Max buckets**, and **Created** date. ### S3 Access The credentials and endpoint you need for any S3 client: - **Endpoint** — `a2-west.americancloud.com` - **Access key** — click **[copy]** to grab it. - **Secret key** — hidden by default. Click **[show]** to reveal, **[copy]** to grab. - **S3 guide** — opens the [s3cmd setup guide](/docs/tutorials/s3cmd-simple-storage-service-command-line-tool-and). ### Buckets Lists all buckets in this unit, with their S3 URL, object count, size, and creation date. ## Set a storage limit To cap how much data the unit can hold (and prevent unexpected charges): 1. On the storage unit detail page, click **Set Limit** in the top right. 2. In the **Set Storage Quota** dialog, enter a **Max size (GB)**. 3. Click **Set Limit**. Leave the field blank to remove an existing limit. ![Set Storage Quota dialog with Max size field](/docs/images/object-storage/a2-object-storage-05.png) ## Create a bucket A bucket is a top-level container for objects. 1. On the storage unit detail page, in the **Buckets** section, click **+ Add Bucket**. 2. In the **Create Bucket** dialog, enter a **Bucket name**. Lowercase letters, numbers, dots, and hyphens; must start and end with a letter or number. 3. Click **Create Bucket**. ![Create Bucket dialog with Bucket name field](/docs/images/object-storage/a2-object-storage-06.png) The bucket appears in the Buckets list with its S3 URL. Click **[copy]** to copy the URL, or **[delete]** to remove the bucket. ![Bucket list with a new bucket and copy/delete actions](/docs/images/object-storage/a2-object-storage-07.png) ## Upload files and create folders Click a bucket in the Buckets list to open it. - **Upload files** — click **Upload** in the top right, or drag and drop files onto the page. - **Create a folder** — click **+ New Folder** in the top right. Folder names allow letters, numbers, dots, hyphens, and underscores. ![Bucket detail page with the New Folder dialog open](/docs/images/object-storage/a2-object-storage-08.png) Uploads are private by default. Use the **Show visibility** toggle to inspect each object's visibility. For uploading from the command line, see the [s3cmd guide](/docs/tutorials/s3cmd-simple-storage-service-command-line-tool-and). ## Share a file To give someone temporary access to an object without exposing your credentials: 1. In the bucket, find the file you want to share and click **[share]** on its row. 2. In the **Share Link** dialog, choose how long the link stays active: **1h**, **6h**, **12h**, or **24h**. 3. Copy the generated link and send it. ![Share Link dialog with expiry options](/docs/images/object-storage/a2-object-storage-09.png) Each file row also has **[download]** to pull the object to your local machine and **[delete]** to remove it. ## Delete a storage unit To remove a storage unit, open its detail page and click **Delete** in the top right. > **Note:** Deleting a storage unit removes all of its buckets and objects. The action cannot be undone. --- # Managed databases Fully managed PostgreSQL, MySQL, and Redis databases ## Create a database 1. Log in to the [American Cloud control panel](https://app.americancloud.com). 2. In the left navigation, select **Databases**. 3. Click **+ Create Database**. 4. Configure the following options: ## Region Choose the region closest to your application workload. | Region | Identifier | |--------|-----------| | US Central | `us-central-0` | | US West (Zone 0) | `us-west-0` | | US West (Zone 1) | `us-west-1` | ## Database engine Select the engine your application requires. - **PostgreSQL** — relational database for structured data and complex queries - **MySQL** — widely compatible relational database - **Redis** — in-memory key-value store for caching and session management ## Availability type | Type | Description | Best for | |------|-------------|----------| | **Development** | Single-node deployment. No data redundancy. Most cost-effective. | Testing and development | | **Data redundancy** | Multi-node cluster. Full data redundancy. Automatic failover. | Production workloads | ## Select a plan **Development plans (PostgreSQL)** | Plan | CPU | Memory | Storage | Replication factor | |------|-----|--------|---------|-------------------| | postgres-small | 5 cores | 4.0 GB | 25 GB | 1 | | postgres-medium | 6 cores | 5.2 GB | 100 GB | 1 | | postgres-large | 8 cores | 12.1 GB | 500 GB | 1 | | postgres-xlarge | 13 cores | 21.3 GB | 1000 GB | 1 | **Data redundancy plans (PostgreSQL)** | Plan | CPU | Memory | Storage | Replication factor | |------|-----|--------|---------|-------------------| | postgres-small | 6 cores | 10.0 GB | 75 GB | 3 | | postgres-medium | 12 cores | 16.9 GB | 300 GB | 3 | | postgres-large | 18 cores | 58.3 GB | 1500 GB | 3 | | postgres-xlarge | 30 cores | 113.5 GB | 3000 GB | 3 | 5. Click **Create Database**. Deployment typically completes in 2–3 minutes. ## Overview Once deployed, click **View Details** on any database to open its management panel. The **Overview** tab shows the current state and configuration of your database. ## Specifications Displays the hardware resources allocated to the active plan. | Field | Description | |-------|-------------| | CPU | Number of vCPU cores | | Memory | RAM in GB | | Storage | Disk size in GB | | Replicas | Number of nodes in the cluster | ## Details | Field | Description | |-------|-------------| | Offering | The plan name (e.g., `postgres-small`) | | Availability | Development or Data Redundancy | | Region | The region the cluster is deployed in | | Created | Date the database was provisioned | ## Network reservation A portion of your project's IP range is reserved for DBaaS services. VMs on the same network are automatically assigned IPs outside the reserved range to prevent conflicts. | Field | Description | |-------|-------------| | Network CIDR | The full CIDR block for the network | | VM Range | IP range assigned to compute instances | | Reserved for DBaaS | IP range held exclusively for database nodes | | Status | Active when the reservation is in place | ## Database status The status badge at the top of the panel reflects the current state. | Status | Meaning | |--------|---------| | **Running** | Database is online and accepting connections | | **Stopped** | Database has been powered down | | **Deploying** | Provisioning is in progress | | **Failed** | An operation encountered an error | ## Actions - **Power Down** — stops the database without deleting it. The button changes to **Power Up** when stopped. - **Refresh** — reloads the current status from the API. ## Connect to your database Open the **Connection** tab to find your credentials and endpoints. ## Endpoints By default, no endpoints are exposed. You must enable a load balancer in **Settings** before connection details appear. | Endpoint type | Access | How to enable | |---------------|--------|---------------| | **Public** | Accessible from the internet | Enable Public Load Balancer in Settings | | **Private** | Accessible within your private network only | Enable Private Load Balancer in Settings | > **Recommendation:** Use a private endpoint for production workloads. Expose a public endpoint only when needed, and restrict access with firewall rules. ## Credentials | Field | Value | |-------|-------| | Username | `postgres` (PostgreSQL default) | | Password | Revealed via **Show Password** in the Connection tab | ## Connection string examples Once your endpoint is active, connect using standard database tooling. **psql (PostgreSQL)** ```bash psql -h -U postgres -d ``` **Connection URI** ``` postgresql://postgres:@:5432/ ``` **Environment variable** ```bash export DATABASE_URL="postgresql://postgres:@:5432/" ``` Replace ``, ``, and `` with the values from the Connection tab. --- See also: [Connect a compute instance to a database](/docs/managed-databases/how-to-connect-vm) ## Backups Open the **Backups** tab to configure backup storage and schedules. Backups are **disabled by default** — a repository must be configured before they activate. ## Backup configuration | Field | Description | |-------|-------------| | Status | Enabled or Disabled depending on whether a repository is configured | | Active Repository | The object storage repository currently receiving backups | | Method | `pg-basebackup` for PostgreSQL | ## Add a backup repository American Cloud Managed Databases integrates with [American Cloud Object Storage](https://americancloud.com/docs/object-storage) for backup storage. 1. Create a storage unit and bucket in [Object Storage](https://app.americancloud.com) if you don't have one already. 2. In the **Backups** tab, click **Add Repository**. 3. Connect your object storage bucket. 4. Once a repository is added, backups are enabled and the Status updates to **Enabled**. > **Recommendation:** Configure backups before your database reaches production traffic. Object Storage is the most cost-effective way to retain point-in-time snapshots. ## Manual backups 1. Go to the **Backups** tab. 2. Click **Trigger Backup** (available once a repository is configured). 3. The backup appears in **Backup History** when complete. ## Backup schedules Automate recurring backups on a defined interval. 1. Go to the **Backups** tab. 2. Click **Create Schedule**. 3. Configure the schedule interval and retention policy. ## Backup history The **Backup History** section lists all completed backups with timestamps and status. Use this to confirm a backup ran successfully before making changes to your database. --- See also: [Enable backups with Object Storage](/docs/managed-databases/how-to-backups) ## Operations The **Operations** tab shows a log of all actions performed on the database cluster. Use it to confirm that a deployment, resize, or configuration change completed successfully. ## Operations log | Column | Description | |--------|-------------| | Operation | The action performed (e.g., `DeployDbaasCluster`, `ResizeDatabase`) | | Status | `Completed`, `In Progress`, or `Failed` | | Started | Timestamp when the operation began | | Completed | Timestamp when the operation finished | | Duration | Total time elapsed | ## Common operations | Operation | Triggered by | |-----------|-------------| | `DeployDbaasCluster` | Creating a new database | | `ResizeDatabase` | Changing the plan or increasing storage | | `EnableLoadBalancer` | Enabling a public or private load balancer | | `DeleteDatabase` | Deleting the database | If any operation shows a **Failed** status, click the **Support** button in the control panel to connect with our team via live chat. ## Settings The **Settings** tab controls load balancer access, database sizing, and deletion. ## Load balancers Enable a load balancer to expose your database. Endpoints appear in the **Connection** tab once enabled. | Option | Description | |--------|-------------| | **Public load balancer** | Exposes the database to the internet via a public IP | | **Private load balancer** | Exposes the database within your private network only | Click **Enable** next to the appropriate option. ## Resize database You can scale your database up without downtime. **Change plan** 1. In **Settings**, click **Change Plan**. 2. Select the new plan. 3. Confirm the change. The operation appears in the **Operations** tab. **Increase storage** 1. In **Settings**, click **Increase Storage**. 2. Enter the new storage size. 3. Confirm. Storage increases are applied immediately. > **Note:** Storage can only be increased, not decreased. Plan changes may cause a brief failover on Data Redundancy clusters. ## Notes - Database names cannot be changed after creation. - Configure backups in the **Backups** tab. ## Delete database > **Warning:** Deletion is permanent and cannot be undone. All data is lost. 1. In **Settings**, scroll to **Danger Zone**. 2. Click **Delete Database**. 3. Confirm the deletion when prompted. --- See also: [Resize a database](/docs/managed-databases/how-to-resize) ## Clusters A cluster is a logical grouping that can contain multiple databases in the same region. Each database in a cluster shares the cluster's network reservation. ## Cluster list view The **Databases** page shows all clusters in your account. Each cluster entry displays: - Cluster name and region - Number of databases in the cluster - Status and plan for each database (Running, Stopped, Deleted) - Quick link to **View Details** for each database ## Add a database to an existing cluster 1. Go to **Databases**. 2. Expand the cluster you want to add to. 3. Click **+ Add Database to this Cluster**. 4. Select the engine, availability type, and plan. 5. Click **Create Database**. The new database deploys into the same region and network as the existing cluster. ## Recently deleted Databases deleted within the last 30 days appear in the **Recently Deleted** section at the bottom of the Databases page. Deleted databases cannot be restored — this section is for reference only. ## How to: Connect a compute instance to a database Use a private endpoint to connect a Cloud Compute instance to your database. This keeps traffic within your private network. ## Prerequisites - A running database in Managed Databases - A Cloud Compute instance on the **same private network** as the database ## Steps 1. Ensure your compute instance and database are on the same private network. 2. In the database **Settings** tab, click **Enable** next to **Private Load Balancer**. 3. Copy the private endpoint from the **Connection** tab. 4. On your compute instance, install the appropriate client: ```bash # PostgreSQL client (Debian/Ubuntu) apt install postgresql-client # MySQL client apt install default-mysql-client ``` 5. Connect using the private endpoint and credentials from the **Connection** tab: ```bash psql -h -U postgres -d ``` ## Notes - The private endpoint is only reachable from within the same network. Do not use it from external machines. - If the connection times out, confirm the Private Load Balancer is enabled and the Status in the **Overview** tab is **Active**. --- See also: [Connect to your database](/docs/managed-databases/connect) · [Settings](/docs/managed-databases/settings) ## How to: Enable backups with Object Storage Backups require an [American Cloud Object Storage](https://americancloud.com/docs/object-storage) bucket as the destination repository. Follow these steps to configure automated backups. ## Prerequisites - A running database in Managed Databases - Access to American Cloud Object Storage ## Steps 1. Go to **Object Storage** in the control panel and create a storage unit if you don't have one. 2. Create a bucket (e.g., `my-db-backups`). 3. Return to your database and open the **Backups** tab. 4. Click **Add Repository** and connect the bucket you created. 5. Once connected, the **Status** in Backup Configuration updates to **Enabled**. 6. Click **Create Schedule** to configure a recurring backup interval and retention policy. ## Verify backups are working 1. In the **Backups** tab, click **Trigger Backup** to run a manual backup immediately. 2. Check **Backup History** — the backup should appear with a `Completed` status within a few minutes. ## Notes - Backups are disabled by default. The **Trigger Backup** button is inactive until a repository is added. - Object Storage buckets must be in the same account as the database. - Configure backups before the database reaches production traffic. --- See also: [Backups](/docs/managed-databases/backups) · [Object Storage docs](https://americancloud.com/docs/object-storage) ## How to: Power down a database Powering down stops the database without deleting it. Useful for pausing a development or staging environment when it's not in use. ## Power down 1. Open the database detail view. 2. Click **Power Down** in the top-right corner of the panel. 3. The status changes to **Stopped**. ## Power up 1. Open the database detail view. 2. Click **Power Up** (the button label changes when the database is stopped). 3. The database returns to **Running** status. ## Notes - Data is preserved when the database is powered down. - Connections to the database will be dropped immediately on power down. - Stopping a database does not reduce your bill — resources remain allocated and billing continues while the database is stopped. - Power down is not a substitute for backups. Always configure a backup repository before stopping a database. --- See also: [Overview](/docs/managed-databases/overview) · [Backups](/docs/managed-databases/backups) ## How to: Resize a database You can scale a database up by changing its plan or increasing storage. Both operations are available in the **Settings** tab. ## Change plan (CPU + Memory + Storage) 1. Open the database and go to **Settings**. 2. Under **Resize Database**, note the current plan. 3. Click **Change Plan**. 4. Select a larger plan from the list. 5. Confirm the change. 6. Monitor progress in the **Operations** tab — the operation appears as `ResizeDatabase`. > **Note:** Plan changes may cause a brief failover on Data Redundancy clusters. Single-node Development clusters will have a short period of unavailability during the resize. ## Increase storage only 1. Open the database and go to **Settings**. 2. Under **Resize Database**, click **Increase Storage**. 3. Enter the new storage size. 4. Confirm. Storage increases are applied immediately with no downtime. ## Constraints - Storage can only be **increased**, not decreased. - Plans can only be changed to a **larger** tier. Downgrading is not supported. - After a resize, the new specs are reflected in the **Overview** tab. --- See also: [Settings](/docs/managed-databases/settings) · [Operations](/docs/managed-databases/operations) ## Troubleshooting ## Cannot connect to the database **Check endpoint configuration** - Go to **Settings** and confirm a load balancer is enabled. - Go to **Connection** and verify an endpoint is listed. **Check network access** - If using a public endpoint, ensure your application's IP is not blocked by a firewall or ACL. - If using a private endpoint, ensure your application is on the same private network as the database. **Check credentials** - Confirm the username (`postgres` for PostgreSQL) and password match what is shown in the **Connection** tab. - Passwords are case-sensitive. --- ## Backups show as disabled - A backup repository must be configured before backups activate. - Go to **Backups** → **Add Repository** and connect an Object Storage bucket. - After adding a repository, the status updates to **Enabled**. See also: [Enable backups with Object Storage](/docs/managed-databases/how-to-backups) --- ## Backup history is empty - Confirm the **Status** in Backup Configuration is **Enabled** (not Disabled). - Click **Trigger Backup** to run a manual backup and verify the repository connection is working. - Check the **Operations** tab for any failed backup operations. --- ## Database is stuck in a non-Running state - Open the **Operations** tab and review recent operations for errors. - If an operation shows **Failed**, open a support ticket from [app.americancloud.com](https://app.americancloud.com) with the operation name and timestamp. --- ## "No backups" warning on the database list This warning appears when no backup repository has been configured. See [Enable backups with Object Storage](/docs/managed-databases/how-to-backups). --- ## Still need help? Open a support ticket from [app.americancloud.com](https://app.americancloud.com) — native English speakers, no ticket queue runaround. --- # SDKs & Terraform Official TypeScript, Go, and Python clients and the Terraform provider for the American Cloud API ## SDKs & Terraform overview American Cloud ships **official, typed SDKs** for the three languages most infrastructure code is written in, plus an **official Terraform provider** for declarative infrastructure as code. All of them derive from the same OpenAPI document that drives the platform API, so they cover the public surface — virtual machines, networking, storage, Kubernetes, DNS, and more — with the same shapes the API actually speaks. | Tool | Package | Install | |---|---|---| | [TypeScript / JavaScript](/docs/sdks/typescript) | `@americancloud/sdk` (npm) | `npm install @americancloud/sdk` | | [Go](/docs/sdks/go) | `github.com/American-Cloud/americancloud-sdk-go` | `go get github.com/American-Cloud/americancloud-sdk-go@latest` | | [Python](/docs/sdks/python) | `americancloud` (PyPI) | `pip install americancloud` | | [Terraform](/docs/sdks/terraform) | `American-Cloud/americancloud` (Terraform Registry) | `required_providers` block — see the [quickstart](/docs/sdks/terraform) | Each language page covers installation, authentication, and working first calls. For the complete operation-by-operation reference, use the [API documentation](https://americancloud.docs.buildwithfern.com/introduction/welcome) — every endpoint there maps directly to an SDK method. ## Authentication All three SDKs authenticate the same way: an **API key pair** passed to the client at construction. Create and manage keys at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). - The **client secret is shown once** at creation — store it securely (an environment variable or secrets manager, never your repo). If it's lost, revoke the key and create a new one. - Keys are **scoped at creation**: `read-only` keys can call `GET` endpoints only; `read-write` keys have full access to resource management. Start integrations with a read-only key and upgrade when you're ready to create resources. ## Versioning: the SDK version is the API version The SDKs are versioned **in lockstep with the platform API**: SDK `1.3.0` is generated from API `1.3.0`. The version you pin tells you exactly which API contract you're coding against — there's no separate compatibility matrix to consult. Pin exact versions and upgrade deliberately; each SDK's changelog describes what changed in the API surface between releases. ## Supply-chain posture The npm and PyPI packages are published via **Trusted Publishing (OIDC)** — no long-lived tokens — and npm releases carry **provenance attestations**, cryptographic proof the package was built from the public repository. The Go module is consumed straight from the public GitHub repo via the Go module proxy. Source for all three lives under [github.com/American-Cloud](https://github.com/American-Cloud). ## SDK, Terraform, or MCP? Three ways in, by how you work: - **SDKs** — you're writing software (services, CI jobs, internal tooling) that manages American Cloud resources imperatively. - **[Terraform](/docs/sdks/terraform)** — you want infrastructure declared in versioned files, with `plan` and `apply` as the change-control loop. The provider is built on the Go SDK, so it inherits the same contract. - **[MCP server](/docs/mcp/overview)** — you want an AI assistant to manage infrastructure conversationally (itself built on the TypeScript SDK); the [Deploy with AI](/docs/deploy-with-ai/overview) recipes show what it can do. ## Next steps - [TypeScript quickstart](/docs/sdks/typescript) - [Go quickstart](/docs/sdks/go) - [Python quickstart](/docs/sdks/python) - [Terraform quickstart](/docs/sdks/terraform) - [API reference](https://americancloud.docs.buildwithfern.com/introduction/welcome) — the full operation-by-operation documentation ## TypeScript SDK quickstart The American Cloud TypeScript SDK is a typed client for the public API, generated from the same OpenAPI specification that drives the platform (via [Fern](https://buildwithfern.com)). It works in both TypeScript and JavaScript projects. For the language-agnostic picture — supply-chain posture, the SDK-vs-MCP decision — see the [SDKs overview](/docs/sdks/overview). ## Install ```sh npm install @americancloud/sdk # or pnpm add @americancloud/sdk ``` The published package is `@americancloud/sdk`. Pin the exact version you install and upgrade deliberately — see [Versioning](#versioning) below. ## Authenticate Every request is signed with an **API key pair** — two values sent as headers. You pass both to the client at construction: | Header | Client option | |---|---| | `X-API-Client-ID` | `apiKey` | | `X-API-Client-Secret` | `apiClientSecret` | Create and manage keys at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). The client secret is shown **once** at creation — store it in an environment variable or secrets manager, never in your repository. If it's lost, revoke the key and create a new one. Keys are scoped when you create them: - **`read-only`** keys can call `GET` endpoints only — listing and reading resources. - **`read-write`** keys have full access, including creating and destroying resources. Start with a read-only key while you're exploring, and switch to read-write when you're ready to provision. Load both values from the environment rather than hard-coding them: ```ts import { AmericancloudApiClient } from "@americancloud/sdk"; const client = new AmericancloudApiClient({ apiKey: process.env.AMERICANCLOUD_API_CLIENT_ID!, apiClientSecret: process.env.AMERICANCLOUD_API_CLIENT_SECRET!, }); ``` The client targets the production API at `https://api.americancloud.com` by default. The client is namespaced by resource — `client.vms`, `client.regions`, `client.sshKeys`, `client.dnsZones`, and so on — and each namespace exposes the operations available on that resource. ## Your first call A read-only key is enough for this. List the regions you can deploy into, then list any VMs on the account: ```ts const regions = await client.regions.listRegions(); for (const region of regions.data) { console.log(`${region.label} — ${region.displayName}`); } const vms = await client.vms.listVms(); console.log(`You have ${vms.total} VM(s).`); ``` Both list calls return a paginated envelope: `total` (the count across all pages) plus a `data` array of items. The `label` on each region is the value you pass as `region` when creating a VM. ## Estimate cost, then create Before creating a VM you can preview its price with `getCostEstimateVms`. It accepts the **same request body** as `createVms`, so you can estimate and create from one object — no surprises on the bill. The estimate is safe to call with a read-only key; the create step needs a read-write key. ```ts const spec = { name: "web-01", region: "us-west-0", vmPackage: "standard-custom", vmSpecs: { vcpu: 2, memoryMb: 2048, rootDiskGb: 50, }, image: "ubuntu-22.04", subscriptionPeriod: "monthly" as const, keypairs: ["my-laptop"], }; // Preview pricing — creates nothing. const estimate = await client.vms.getCostEstimateVms(spec); console.log("Monthly total:", estimate.estimates.monthly.total); console.log("Hourly total:", estimate.estimates.hourly.total); // Happy with the number? Create it with the same object. const vm = await client.vms.createVms(spec); console.log("Created VM:", vm); ``` The estimate response splits cost into `estimates.hourly` and `estimates.monthly`, each with `base`, `discount`, and `total` fields. The `keypairs` array references SSH key pairs by name — list yours with `client.sshKeys.listSshKeys()` or create one through the same namespace. `subscriptionPeriod` accepts `"hourly"` or `"monthly"`. ## Handle errors Failed calls **throw**. The base error type is `AmericancloudApiError`, exported from the package root; it carries the HTTP `statusCode`, the parsed response `body`, and a human-readable `message`. Catch it to branch on the status: ```ts import { AmericancloudApiError } from "@americancloud/sdk"; try { const vm = await client.vms.getVms({ id: "does-not-exist" }); console.log(vm); } catch (err) { if (err instanceof AmericancloudApiError) { console.error(`API error ${err.statusCode}:`, err.body); if (err.statusCode === 404) { // Resource doesn't exist (or isn't yours). } } else { throw err; // network/abort error — re-throw or handle separately } } ``` `err.statusCode` is the standard HTTP status — `400` for a bad request, `401` for a missing or invalid key, `403` when your key's scope doesn't permit the operation (e.g. a read-only key calling a create endpoint), `404` for a resource that doesn't exist, and `409` for a conflicting state. ## Pagination List endpoints accept optional `page` (1-indexed, defaults to `1`) and `pageSize` (defaults to `100`, server cap `500`) parameters, and return `total` alongside the `data` array. Compare how many items you've collected against `total` to walk every page: ```ts async function listAllVms() { const all = []; let page = 1; const pageSize = 100; while (true) { const res = await client.vms.listVms({ page, pageSize }); all.push(...res.data); if (all.length >= res.total) break; page += 1; } return all; } ``` ## Versioning The SDK version is generated in **lockstep with the API**: SDK `1.3.0` is generated from API version `1.3.0`, so the version you install tells you exactly which API surface you're coding against. Patch and minor releases are backward-compatible and safe to upgrade; a major release tracks a new API URL version and may require code changes. Pin an exact version and upgrade on your own schedule. The [SDKs overview](/docs/sdks/overview) covers the full versioning policy. Because additive API changes (new endpoints, optional fields, new enum values) can ship within a major version, write code that tolerates unknown response fields and unrecognized enum values gracefully. ## Next steps - [SDKs overview](/docs/sdks/overview) — versioning policy, supply-chain posture, and the SDK-vs-MCP decision - [Go quickstart](/docs/sdks/go) and [Python quickstart](/docs/sdks/python) — the same API in two more languages - [API reference](https://americancloud.docs.buildwithfern.com/introduction/welcome) — every endpoint, request shape, and response shape, each mapping directly to an SDK method - [Source on GitHub](https://github.com/American-Cloud/americancloud-sdk-typescript) — report issues or browse the generated client - [MCP server](/docs/mcp/overview) — if you want an AI assistant to manage infrastructure conversationally instead of writing code, this is the path (it's built on this SDK) ## Go SDK quickstart The American Cloud Go SDK is a typed client for the platform API, generated from the same OpenAPI document that drives the API itself. This page gets you from `go get` to a working program. For the bigger picture — how the three SDKs relate, the auth model, and supply-chain posture — see the [SDKs overview](/docs/sdks/overview). ## Install The module requires Go 1.21 or newer. ```sh go get github.com/American-Cloud/americancloud-sdk-go@latest ``` We recommend pinning an exact release and upgrading deliberately rather than tracking `@latest`: ```sh go get github.com/American-Cloud/americancloud-sdk-go@v1.3.0 ``` ## Authenticate Every request needs **both** parts of an API key pair. Create and manage keys at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). The client secret is shown once at creation — store it securely (an environment variable or secrets manager, never your repo). If it's lost, revoke the key and create a new one. Keys are scoped at creation. A **read-only** key can call `GET` endpoints only; a **read-write** key has full access to resource management. Start with a read-only key and upgrade when you're ready to create resources. Pass the pair to the client through `option.WithAPIKey` (the client ID) and `option.WithAPIClientSecret`. Reading them from the environment keeps secrets out of source: ```sh export AMERICANCLOUD_API_CLIENT_ID="your-client-id" export AMERICANCLOUD_API_CLIENT_SECRET="your-client-secret" ``` ## First call: list regions This complete program constructs a client and lists the regions you can deploy into — a read-only call, so a read-only key is enough. ```go package main import ( "context" "fmt" "log" "os" americancloud "github.com/American-Cloud/americancloud-sdk-go/client" "github.com/American-Cloud/americancloud-sdk-go/option" ) func main() { client := americancloud.NewClient( option.WithAPIKey(os.Getenv("AMERICANCLOUD_API_CLIENT_ID")), option.WithAPIClientSecret(os.Getenv("AMERICANCLOUD_API_CLIENT_SECRET")), ) regions, err := client.Regions.ListRegions(context.Background(), nil) if err != nil { log.Fatal(err) } for _, region := range regions.Data { fmt.Printf("%s — %s\n", region.Label, region.DisplayName) } } ``` Every method takes a `context.Context` as its first argument, so requests participate in your timeouts and cancellation. The client is namespaced by resource — `client.Regions`, `client.Vms`, `client.SSHKeys`, `client.DNSZones`, `client.BlockStorage`, and so on. ## Estimate cost, then create a VM You can preview pricing for an exact spec before committing to it. `GetCostEstimateVms` accepts the same body as create (`CreateVMDto`) and returns an estimate without provisioning anything. This is a read-write program — the create step needs a read-write key. ```go package main import ( "context" "fmt" "log" "os" americancloudsdkgo "github.com/American-Cloud/americancloud-sdk-go" americancloud "github.com/American-Cloud/americancloud-sdk-go/client" "github.com/American-Cloud/americancloud-sdk-go/option" ) func main() { client := americancloud.NewClient( option.WithAPIKey(os.Getenv("AMERICANCLOUD_API_CLIENT_ID")), option.WithAPIClientSecret(os.Getenv("AMERICANCLOUD_API_CLIENT_SECRET")), ) ctx := context.Background() spec := &americancloudsdkgo.CreateVMDto{ Name: "web-01", Region: "us-west-0", VMPackage: "standard-custom", Image: "ubuntu-22.04", VMSpecs: &americancloudsdkgo.VMSpecsDto{ Vcpu: 2, MemoryMb: 4096, RootDiskGb: 40, }, SubscriptionPeriod: americancloudsdkgo.CreateVMDtoSubscriptionPeriodMonthly, Keypairs: []string{"deploy-key"}, } estimate, err := client.Vms.GetCostEstimateVms(ctx, spec) if err != nil { log.Fatal(err) } fmt.Printf("Estimated monthly total: %.2f\n", estimate.Estimates.Monthly.Total) vm, err := client.Vms.CreateVms(ctx, spec) if err != nil { log.Fatal(err) } fmt.Printf("Created VM %s (%s) — status %s\n", vm.ID, vm.Name, vm.Status) } ``` Use real `region`, `image`, and `vmPackage` labels from `client.Regions.ListRegions`, `client.Images.ListImages`, and `client.VMPackages.ListVMPackages`. The estimate response also carries an optional `BillingNote` and `DiscountApplied` when applicable. `CreateVMDto` exposes more optional fields (tags, an attached `Network`, base64 cloud-init `Userdata`); the ones above are the minimum to provision. ## Handle errors Failed calls return an error you can match against typed values for each HTTP status — `BadRequestError`, `UnauthorizedError`, `ForbiddenError`, `NotFoundError`, `ConflictError`, `InternalServerError`, and `GatewayTimeoutError`. Use `errors.As` to branch on the kind, and read the decoded body for a message: ```go import ( "errors" "fmt" americancloudsdkgo "github.com/American-Cloud/americancloud-sdk-go" ) vm, err := client.Vms.GetVms(ctx, &americancloudsdkgo.GetVmsRequest{ID: "vm-123"}) if err != nil { var notFound *americancloudsdkgo.NotFoundError if errors.As(err, ¬Found) { fmt.Println("no such VM:", notFound.Body.GetMessage()) return } return err } ``` Each typed error embeds the SDK's `core.APIError`, so its `StatusCode` field is always available even when you don't need to distinguish the specific kind. ## Paginate list endpoints List calls are page-based. The request struct takes optional `Page` (1-indexed, defaults to 1) and `PageSize` (defaults to 100, server cap 500) pointers, and the response carries `Total` — the count across all pages — alongside the current page's `Data`. Use the SDK's pointer helpers to set the optional fields: ```go import americancloudsdkgo "github.com/American-Cloud/americancloud-sdk-go" page := 1 for { resp, err := client.Vms.ListVms(ctx, &americancloudsdkgo.ListVmsRequest{ Page: americancloudsdkgo.Int(page), PageSize: americancloudsdkgo.Int(100), }) if err != nil { return err } for _, vm := range resp.Data { fmt.Printf("%s\t%s\t%s\n", vm.ID, vm.Name, vm.Status) } if float64(page*100) >= resp.Total { break } page++ } ``` Passing `nil` as the request fetches the first page with default sizing. ## Versioning The SDK version is the API version: SDK `1.3.0` is generated from API `1.3.0`, in lockstep with the TypeScript and Python clients. The `1.x` line targets API `v1`. Patch and minor releases are backward-compatible and safe to upgrade; a major release tracks a new API URL version and is the only release that can require code changes. Write code that tolerates unknown response fields and new enum values gracefully — additive changes ship within a version. See [SDKs overview](/docs/sdks/overview) for the full policy. ## Next steps - [SDKs overview](/docs/sdks/overview) — auth model, versioning, and supply-chain posture across all three languages - [TypeScript quickstart](/docs/sdks/typescript) and [Python quickstart](/docs/sdks/python) - [API reference](https://americancloud.docs.buildwithfern.com/introduction/welcome) — the full operation-by-operation documentation; every endpoint maps to an SDK method - [github.com/American-Cloud/americancloud-sdk-go](https://github.com/American-Cloud/americancloud-sdk-go) — source, changelog, and issues - [MCP server](/docs/mcp/overview) — manage infrastructure conversationally with an AI assistant ## Python SDK quickstart The official American Cloud Python SDK is a typed client for the public API, generated from the same OpenAPI document that drives the platform. It covers virtual machines, regions, SSH keys, DNS, networking, and more. For the language-agnostic picture — authentication model, versioning policy, and supply-chain posture — see the [SDKs overview](/docs/sdks/overview). ## Install The SDK is published to PyPI as `americancloud`: ```sh pip install americancloud ``` It requires Python 3.9+ and brings its own HTTP and validation dependencies (httpx, pydantic). Pin an exact version and upgrade deliberately — see [Versioning](#versioning) below. ## Authenticate Every request needs **both** parts of an API key pair. Create and manage keys at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). The client secret is shown **once** at creation — store it in an environment variable or a secrets manager, never in your repo. If it's lost, revoke the key and create a new one. Keys are scoped at creation: - **read-only** — can call `GET` endpoints only (list and read operations). - **read-write** — full access, including creating and deleting resources. Start an integration with a read-only key and upgrade when you're ready to provision. Pass the pair to the client as `api_key` (the client ID) and `api_client_secret`: ```python import os from americancloud import AmericancloudApi client = AmericancloudApi( api_key=os.environ["AMERICANCLOUD_API_CLIENT_ID"], api_client_secret=os.environ["AMERICANCLOUD_API_CLIENT_SECRET"], ) ``` The client targets `https://api.americancloud.com` by default; pass `base_url=...` to override it. ## Your first call A read-only key is enough for everything in this section. List the regions available to your account: ```python regions = client.regions.list_regions() for region in regions.data: print(region.label) ``` The client is namespaced by resource — `client.regions`, `client.vms`, `client.ssh_keys`, `client.dns_zones`, `client.dns_records`, and more. List methods return a page object whose items live on `.data` (see [Pagination](#pagination)). ## Estimate cost, then create Before provisioning, preview pricing with `get_cost_estimate_vms`. It accepts the same body as the create call but doesn't create anything — so it's safe to call with a read-only key while you tune specs: ```python from americancloud import VmSpecsDto spec = dict( name="web-01", region="us-west-0", vm_package="standard-custom", vm_specs=VmSpecsDto(vcpu=2.0, memory_mb=2048, root_disk_gb=50), image="ubuntu-22.04", subscription_period="hourly", ) estimate = client.vms.get_cost_estimate_vms(**spec) print(estimate.estimates.hourly.total) print(estimate.estimates.monthly.total) ``` The estimate exposes `estimates.hourly` and `estimates.monthly`, each with `base`, `discount`, and `total`. Once the numbers look right, the same body creates the VM (this needs a **read-write** key): ```python vm = client.vms.create_vms( name="web-01", region="us-west-0", vm_package="standard-custom", vm_specs=VmSpecsDto(vcpu=2.0, memory_mb=2048, root_disk_gb=50), image="ubuntu-22.04", subscription_period="hourly", keypairs=["my-ssh-key"], ) print(vm) ``` `keypairs` takes the **names** of SSH key pairs already on your account. To create one first — generating a new key pair and returning the private key once — call `create_ssh_keys` with just a name, or pass `public_key=...` to register a key you already hold: ```python key = client.ssh_keys.create_ssh_keys(name="my-ssh-key") ``` ## Async usage For an asyncio application, use `AsyncAmericancloudApi`. It exposes the same namespaces and method names; each call is awaited: ```python import asyncio import os from americancloud import AsyncAmericancloudApi async def main(): client = AsyncAmericancloudApi( api_key=os.environ["AMERICANCLOUD_API_CLIENT_ID"], api_client_secret=os.environ["AMERICANCLOUD_API_CLIENT_SECRET"], ) regions = await client.regions.list_regions() for region in regions.data: print(region.label) asyncio.run(main()) ``` ## Error handling Failed calls raise a typed exception. Each subclass carries `status_code`, `body`, and `headers`: ```python from americancloud import NotFoundError, UnauthorizedError try: region = client.regions.get_regions(id="123e4567-e89b-12d3-a456-426614174000") except NotFoundError as err: print("Region not found:", err.status_code) except UnauthorizedError as err: print("Check your API key pair:", err.body) ``` The available subclasses are `BadRequestError` (400), `UnauthorizedError` (401), `ForbiddenError` (403), `NotFoundError` (404), `ConflictError` (409), `InternalServerError` (500), and `GatewayTimeoutError` (504). To catch any API failure in one handler, catch the common base class: ```python from americancloud.core.api_error import ApiError try: client.vms.list_vms() except ApiError as err: print(err.status_code, err.body) ``` ## Pagination List methods accept `page` (1-indexed, defaults to 1) and `page_size` (defaults to 100; server cap 500). The response carries the items on `.data` and the full match count on `.total`, so you can compute how many pages exist: ```python import math page_size = 100 first = client.vms.list_vms(page=1, page_size=page_size) pages = math.ceil(first.total / page_size) all_vms = list(first.data) for page in range(2, pages + 1): more = client.vms.list_vms(page=page, page_size=page_size) all_vms.extend(more.data) ``` ## Versioning The SDK version is **the same as the API platform version it was generated from** — SDK `1.3.0` is generated from API `1.3.0`, so the version you pin tells you exactly which API contract you're coding against. Patch and minor releases are backward-compatible and safe to upgrade; a major release tracks a new API URL version and may require code changes. The full policy is in the [SDKs overview](/docs/sdks/overview#versioning-the-sdk-version-is-the-api-version). Write code that tolerates unknown response fields and unrecognized enum values gracefully — additive API changes can ship within a version. ## Next steps - [SDKs overview](/docs/sdks/overview) — authentication, versioning, and supply-chain details shared across all three SDKs - [TypeScript quickstart](/docs/sdks/typescript) - [Go quickstart](/docs/sdks/go) - [API reference](https://americancloud.docs.buildwithfern.com/introduction/welcome) — every endpoint, with code samples, maps directly to an SDK method - [Source on GitHub](https://github.com/American-Cloud/americancloud-sdk-python) - [MCP server](/docs/mcp/overview) — manage infrastructure conversationally from an AI assistant ## Terraform provider quickstart The American Cloud Terraform provider lets you declare your infrastructure — VMs, block storage, networking, Kubernetes, and DNS — as code and reconcile it with `terraform apply`. It's built on the same Go SDK and platform API as the other clients, so the resources map directly to the API surface. For the bigger picture on how the SDKs relate and how auth works, see the [SDKs overview](/docs/sdks/overview). This page gets you from an empty directory to a running VM. For the full, attribute-by-attribute reference of every resource and data source, see the [provider page on the Terraform Registry](https://registry.terraform.io/providers/American-Cloud/americancloud). ## Install Declare the provider in a `terraform` block and run `terraform init`. We recommend pinning to the `0.1` line and upgrading deliberately: ```hcl terraform { required_providers { americancloud = { source = "American-Cloud/americancloud" version = "~> 0.1" } } } provider "americancloud" { # Credentials are read from the environment by default — see below. } ``` ```sh terraform init ``` `init` downloads the provider from the [Terraform Registry](https://registry.terraform.io/providers/American-Cloud/americancloud) and records it in your lock file. ## Authenticate The provider needs **both** parts of an API key pair. Create and manage keys at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). The client secret is shown once at creation — store it securely. If it's lost, revoke the key and create a new one. The default and recommended path is environment variables, which keeps secrets out of your `.tf` files and state: ```sh export AMERICANCLOUD_API_CLIENT_ID="your-client-id" export AMERICANCLOUD_API_CLIENT_SECRET="your-client-secret" ``` The provider block accepts the same values as explicit arguments — `api_client_id`, `api_client_secret`, and an optional `api_url` override — but prefer the environment for credentials. Hard-coding a secret in `api_client_secret` puts it in version control and in plan output. ```hcl provider "americancloud" { # Optional overrides; credentials are best left to the environment. # api_client_id = "..." # api_client_secret = "..." # api_url = "https://api.americancloud.com" } ``` ## A first configuration This config looks up a region and image, registers an SSH key, and provisions a reachable VM. Omitting `network` has the platform auto-create an isolated network, and `network_access` opens inbound ports on that network's public IP. Use real `label` values from the registry's data sources (`americancloud_region`, `americancloud_image`, `americancloud_vm_package`). ```hcl data "americancloud_region" "west" { label = "us-west-0" } data "americancloud_image" "ubuntu" { label = "ubuntu-24.04-050826" } resource "americancloud_ssh_key" "deploy" { name = "deploy-key" public_key = file("~/.ssh/id_ed25519.pub") } resource "americancloud_vm" "web" { name = "web-1" region = data.americancloud_region.west.label image = data.americancloud_image.ubuntu.label vm_package = "standard-custom" vcpu = 1 memory_mb = 2048 root_disk_gb = 25 subscription_period = "hourly" keypairs = [americancloud_ssh_key.deploy.name] network_access = { allow_egress_all = true inbound_ports = [ { port = 22, protocol = "TCP" }, { port = 443, protocol = "TCP" }, ] } } output "vm_ip" { value = americancloud_vm.web.ip_address } ``` ## Plan and apply Preview the changes, then apply them. A VM provisions asynchronously, so `apply` blocks until it's running. ```sh terraform plan # review what will be created terraform apply # provision it ``` When you're done, `terraform destroy` tears the stack back down. Note that an auto-created network (from omitting `network`) is not managed by Terraform and survives the VM. ## Create-only attributes and import A few VM attributes are **create-only** (they force replacement if changed): `keypairs`, `user_data`, `tags`, and `network_access`. The platform applies them at create time, but the read API doesn't echo them back. As a practical consequence, `terraform import` can't recover these four — importing a VM under a config that sets them will plan a replacement, because there's nothing on the read side to match your config against. This is expected: import recovers the VM's identity and computed fields, but you'll want to align create-only attributes deliberately rather than relying on import to round-trip them. Plain resources like SSH keys, DNS records, and networks import cleanly. ## State and secrets hygiene Terraform state can contain sensitive values — a generated SSH `private_key`, for example, is returned once at creation and stored in state. Treat state as a secret: - Keep API credentials in environment variables, **never** in `.tf` files committed to version control. - Use a remote state backend with encryption at rest and access controls, rather than a local `terraform.tfstate` in a shared repo. - Avoid printing sensitive outputs in CI logs; mark outputs `sensitive = true` where appropriate. ## Versioning The provider carries **its own semantic version**, independent of the SDK and API version numbers. Its compatibility contract is the exact-pinned [Go SDK](/docs/sdks/go) it's built on — which is itself in lockstep with the API platform version — so the provider release transitively states the API surface it was built and tested against. Patch releases are documentation or internal fixes, minor releases add resources or absorb additive SDK changes, and major releases cover removed or renamed resources and changed attribute shapes. Breaking attribute changes that could force resource replacement are called out prominently in the changelog. Pin to a range like `~> 0.1` and upgrade deliberately. ## Next steps - [SDKs overview](/docs/sdks/overview) — the auth model, versioning, and supply-chain posture shared across all clients - [TypeScript quickstart](/docs/sdks/typescript), [Go quickstart](/docs/sdks/go), and [Python quickstart](/docs/sdks/python) - [Terraform Registry](https://registry.terraform.io/providers/American-Cloud/americancloud) — the full reference for every resource and data source - [MCP server](/docs/mcp/overview) — manage infrastructure conversationally with an AI assistant - [github.com/American-Cloud/terraform-provider-americancloud](https://github.com/American-Cloud/terraform-provider-americancloud) — source, changelog, and issues --- # MCP server Manage American Cloud from Claude, Cursor, and other AI assistants ## Overview The **American Cloud MCP server** connects AI assistants to your cloud. It implements the [Model Context Protocol](https://modelcontextprotocol.io) — an open standard supported by Claude Desktop, Claude Code, Cursor, Codex, Windsurf, VS Code, and a growing list of clients — so your assistant can inventory, audit, provision, and manage your American Cloud infrastructure in plain English. The server runs **locally on your machine**. Your API keys go directly from your environment to the American Cloud API — no hosted middleman in between. It's open source (Apache-2.0) at [github.com/American-Cloud/americancloud-mcp](https://github.com/American-Cloud/americancloud-mcp) and published to npm with provenance attestation. ## Prerequisites - **Node.js 20 or newer** — the server runs via `npx` - **An American Cloud API key** — create one at [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) Start with a **read-only API key**. The assistant can explore and audit everything but cannot change anything — switch to a read-write key later if you want it to manage resources. See [Safety](#safety-read-only-by-default). ## Quick start Add this block to your MCP client's configuration: ```json { "mcpServers": { "americancloud": { "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "your-client-id", "AMERICANCLOUD_API_CLIENT_SECRET": "your-client-secret" } } } } ``` Then restart your client and ask: *"What regions can I deploy to on American Cloud?"* Step-by-step instructions per client: - [Claude Desktop](/docs/mcp/claude-desktop) - [Claude Code](/docs/mcp/claude-code) - [Cursor](/docs/mcp/cursor) - [Codex](/docs/mcp/codex) - [Windsurf, VS Code, and other clients](/docs/mcp/other-clients) ## Service groups The server provides 175 tools across 7 service groups. By default the core infrastructure groups are enabled: **compute, storage, networking, kubernetes**. Scope or extend the list with the `--services` flag: ```sh npx @americancloud/mcp --services all npx @americancloud/mcp --services compute,dns ``` | Group | Tools | Covers | |---|---|---| | `compute` *(default)* | 25 | VMs, packages, images, regions, SSH keys | | `storage` *(default)* | 24 | block storage, snapshots, object storage | | `networking` *(default)* | 57 | isolated/VPC networks, VPC tiers, public IPs, firewall, port forwarding, load balancers, egress, ACLs | | `kubernetes` *(default)* | 11 | managed Kubernetes clusters | | `databases` | 36 | MySQL/PostgreSQL/Redis database clusters, backups, infrastructure, offerings | | `wordpress` | 15 | managed WordPress | | `dns` | 7 | hosted DNS zones and records | In your client config, flags go in the `args` array: ```json "args": ["-y", "@americancloud/mcp", "--services", "all"] ``` Scoping with `--services` keeps the tool list small, which helps clients with limited context windows pick the right tool. ## Safety: read-only by default The server lets an AI assistant work with **real infrastructure and real billing**, so it is deliberately conservative out of the box: - **Read-only by default.** Only read tools (list, get, cost estimates) are registered until you add `"--allow-writes"` to `args`. Without it, the assistant can explore and inspect but cannot create, modify, or delete anything. - **Use the narrowest key.** With a **read-only API key**, writes are impossible at the account level regardless of any flag. Only pair a read-write key with `--allow-writes` when you actually want the assistant to make changes. - **Destructive tools are flagged.** Delete, release, reinstall, and similar irreversible operations are marked destructive, so MCP clients that support confirmations will prompt you before running them. ```json "args": ["-y", "@americancloud/mcp", "--allow-writes"] ``` A few read tools return credentials by design — for example fetching a Kubernetes cluster config or a database connection string. Their tool descriptions are labeled accordingly. Read-only mode means the assistant cannot *change* your infrastructure; treat retrieved credentials with the same care as any other secret. ## Environment variables | Variable | Required | Purpose | |---|---|---| | `AMERICANCLOUD_API_CLIENT_ID` | yes | API client ID | | `AMERICANCLOUD_API_CLIENT_SECRET` | yes | API client secret | ## Verifying the connection After setup, ask your assistant to call the built-in `get_server_info` tool, or just ask a simple question: > "What regions can I deploy to on American Cloud?" If the assistant lists regions, you're connected. For ideas on what to do next, see [Things to try](/docs/mcp/use-cases). ## Versioning and source The server is versioned independently of the platform API; each release states the API surface it targets. Release notes, source, and issue tracking live on [GitHub](https://github.com/American-Cloud/americancloud-mcp). ## Claude Desktop This guide connects the [Claude Desktop](https://claude.ai/download) app to American Cloud, so you can manage your infrastructure in a Claude conversation. ## Prerequisites - Claude Desktop (macOS or Windows) - Node.js 20 or newer installed (`node --version` to check) - An American Cloud API key from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) — start with a **read-only** key ## Configure 1. Open Claude Desktop **Settings**, go to the **Developer** tab, and click **Edit Config**. This opens (or creates) the config file: - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%\Claude\claude_desktop_config.json` 2. Add the American Cloud server to the `mcpServers` block: ```json { "mcpServers": { "americancloud": { "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "your-client-id", "AMERICANCLOUD_API_CLIENT_SECRET": "your-client-secret" } } } } ``` 3. Save the file and **fully restart Claude Desktop** (quit and reopen — closing the window is not enough). 4. In a new conversation, open the tools menu (the sliders icon in the input box). You should see **americancloud** listed with its tools. ## Verify Ask Claude: > "What regions can I deploy to on American Cloud?" Claude will ask permission to use the American Cloud tools the first time, then list your available regions. ## Enable resource management (optional) By default the server is read-only — Claude can inspect and audit your infrastructure but cannot change it. To let Claude create and manage resources, use a **read-write API key** and add the `--allow-writes` flag: ```json "args": ["-y", "@americancloud/mcp", "--allow-writes"] ``` Claude Desktop will still ask for your confirmation before running tools, and destructive operations (like deleting a VM) are explicitly flagged. ## Troubleshooting - **Server doesn't appear after restart** — validate the JSON (a trailing comma is the most common culprit), then check the MCP logs: **Settings → Developer**, or the log files in `~/Library/Logs/Claude/` (macOS) / `%APPDATA%\Claude\logs\` (Windows). - **`npx` not found** — Claude Desktop launches the server with your system's Node.js. Make sure `node --version` works in a fresh terminal; if you installed Node via a version manager, you may need to provide the full path to `npx` in `command`. - **Authentication errors** — re-check both env values against [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys). ## Next steps - [Things to try](/docs/mcp/use-cases) — prompt ideas from quick audits to full provisioning - [Overview](/docs/mcp/overview) — service groups, `--services` scoping, and safety details ## Claude Code This guide connects [Claude Code](https://claude.com/claude-code) — Anthropic's agentic coding tool — to American Cloud. Claude Code is the most powerful pairing for the MCP server: it can manage your infrastructure *and* run commands in your terminal, so it can provision a server and deploy to it in the same session. ## Prerequisites - Claude Code installed - Node.js 20 or newer - An American Cloud API key from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) — start with a **read-only** key ## Configure Add the server with one command: ```sh claude mcp add americancloud \ --env AMERICANCLOUD_API_CLIENT_ID=your-client-id \ --env AMERICANCLOUD_API_CLIENT_SECRET=your-client-secret \ -- npx -y @americancloud/mcp ``` By default this configures the server for the current project only. To make it available in every project, add `--scope user`: ```sh claude mcp add americancloud --scope user \ --env AMERICANCLOUD_API_CLIENT_ID=your-client-id \ --env AMERICANCLOUD_API_CLIENT_SECRET=your-client-secret \ -- npx -y @americancloud/mcp ``` ## Verify Inside a Claude Code session, run `/mcp` to see the server's connection status and tools, or just ask: > What regions can I deploy to on American Cloud? ## Sharing with your team To check the server into a repository so teammates get it automatically, use `--scope project`, which writes a `.mcp.json` file at the project root. Reference environment variables instead of hardcoding secrets: ```json { "mcpServers": { "americancloud": { "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "${AMERICANCLOUD_API_CLIENT_ID}", "AMERICANCLOUD_API_CLIENT_SECRET": "${AMERICANCLOUD_API_CLIENT_SECRET}" } } } } ``` Each teammate sets the two variables in their own shell environment, with their own key. Never commit a real client secret. The `${VAR}` form is expanded by Claude Code from each user's environment at launch. ## Enable resource management (optional) By default the server is read-only. To let Claude Code create and manage resources, use a **read-write API key** and add `--allow-writes` after the package name: ```sh claude mcp add americancloud \ --env AMERICANCLOUD_API_CLIENT_ID=your-client-id \ --env AMERICANCLOUD_API_CLIENT_SECRET=your-client-secret \ -- npx -y @americancloud/mcp --allow-writes ``` Claude Code asks permission before each tool call (configurable per tool), and destructive operations are explicitly flagged. ## The build-and-deploy workflow Where this setup shines: Claude Code combines American Cloud tools with your terminal. A single session can: 1. Write or modify your application code 2. Create a VM with your SSH key, configure firewall rules, and point DNS at it — via the MCP server 3. Deploy and verify over SSH — via your shell Try: > Create a small Ubuntu VM in us-west with my SSH key, open ports 22 and 80, wait for it to come up, then install nginx over SSH and confirm it serves the default page. Or for Kubernetes: > Fetch the kubeconfig for my production cluster and check whether all deployments are healthy. ## Next steps - [Things to try](/docs/mcp/use-cases) — more prompt ideas - [Overview](/docs/mcp/overview) — service groups, `--services` scoping, and safety details ## Cursor This guide connects [Cursor](https://cursor.com) to American Cloud, so Cursor's agent can inspect and manage your infrastructure alongside your code. ## Prerequisites - Cursor installed - Node.js 20 or newer - An American Cloud API key from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) — start with a **read-only** key ## Configure Cursor reads MCP servers from a JSON file at either level: - **Project**: `.cursor/mcp.json` in your repository (applies to that project) - **Global**: `~/.cursor/mcp.json` in your home directory (applies everywhere) Create the file (or open **Cursor Settings → MCP → Add new MCP server**) and add: ```json { "mcpServers": { "americancloud": { "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "your-client-id", "AMERICANCLOUD_API_CLIENT_SECRET": "your-client-secret" } } } } ``` If you use a project-level `.cursor/mcp.json` in a shared repository, don't put a real secret in it — keep the server config global instead, or add the file to `.gitignore`. Cursor detects the change automatically; if the server doesn't appear, toggle it in **Cursor Settings → MCP** or restart Cursor. ## Verify Open the agent panel and ask: > What regions can I deploy to on American Cloud? The agent will request approval to run the American Cloud tool the first time. ## Enable resource management (optional) By default the server is read-only. To let the agent create and manage resources, use a **read-write API key** and add the flag: ```json "args": ["-y", "@americancloud/mcp", "--allow-writes"] ``` Cursor asks for approval before tool calls unless you've enabled auto-run, and destructive operations are explicitly flagged. We recommend keeping approval on for write-enabled setups. ## Next steps - [Things to try](/docs/mcp/use-cases) — prompt ideas from quick audits to full provisioning - [Overview](/docs/mcp/overview) — service groups, `--services` scoping, and safety details ## Codex This guide connects [Codex](https://developers.openai.com/codex) — OpenAI's agentic coding CLI — to American Cloud. Like Claude Code, Codex runs in your terminal, so a single session can both manage your infrastructure through the MCP server and run commands on your machine — provision a server and deploy to it without leaving the CLI. ## Prerequisites - Codex CLI installed (`codex --version` to check) - Node.js 20 or newer — the MCP server runs via `npx` - An American Cloud API key from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) — start with a **read-only** key ## Configure Add the server with one command: ```sh codex mcp add americancloud \ --env AMERICANCLOUD_API_CLIENT_ID=your-client-id \ --env AMERICANCLOUD_API_CLIENT_SECRET=your-client-secret \ -- npx -y @americancloud/mcp ``` This writes the server into your Codex config at `~/.codex/config.toml`. You can also add or edit the entry by hand: ```toml [mcp_servers.americancloud] command = "npx" args = ["-y", "@americancloud/mcp"] [mcp_servers.americancloud.env] AMERICANCLOUD_API_CLIENT_ID = "your-client-id" AMERICANCLOUD_API_CLIENT_SECRET = "your-client-secret" ``` The first launch runs `npx`, which downloads the package before the server starts. Codex's default startup timeout is 10 seconds — if the first start times out on a cold cache, raise it by adding `startup_timeout_sec = 30` under `[mcp_servers.americancloud]`. ## Verify List the configured servers to confirm it registered: ```sh codex mcp list ``` Then start a Codex session and ask: > What regions can I deploy to on American Cloud? Codex will ask for approval to run the American Cloud tool the first time. ## Enable resource management (optional) By default the server is read-only. To let Codex create and manage resources, use a **read-write API key** and add the `--allow-writes` flag after the package name — via the CLI: ```sh codex mcp add americancloud \ --env AMERICANCLOUD_API_CLIENT_ID=your-client-id \ --env AMERICANCLOUD_API_CLIENT_SECRET=your-client-secret \ -- npx -y @americancloud/mcp --allow-writes ``` Or in `~/.codex/config.toml`: ```toml args = ["-y", "@americancloud/mcp", "--allow-writes"] ``` Codex asks for approval before running tools (depending on your approval mode), and destructive operations are explicitly flagged. We recommend keeping approvals on for write-enabled setups. ## The build-and-deploy workflow Where this setup shines: Codex combines American Cloud tools with your terminal. A single session can: 1. Write or modify your application code 2. Create a VM with your SSH key, configure firewall rules, and point DNS at it — via the MCP server 3. Deploy and verify over SSH — via your shell Try: > Create a small Ubuntu VM in us-west with my SSH key, open ports 22 and 80, wait for it to come up, then install nginx over SSH and confirm it serves the default page. Or for Kubernetes: > Fetch the kubeconfig for my production cluster and check whether all deployments are healthy. ## Next steps - [Things to try](/docs/mcp/use-cases) — prompt ideas from quick audits to full provisioning - [Overview](/docs/mcp/overview) — service groups, `--services` scoping, and safety details ## Other clients The American Cloud MCP server works with **any client that supports MCP stdio servers**. This page covers Windsurf and VS Code, plus the generic configuration that applies to everything else. In every case you need: - Node.js 20 or newer - An American Cloud API key from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) — start with a **read-only** key ## Windsurf Windsurf reads MCP servers from `~/.codeium/windsurf/mcp_config.json`. Open it from the Cascade panel (MCP icon → **Configure**) or edit it directly: ```json { "mcpServers": { "americancloud": { "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "your-client-id", "AMERICANCLOUD_API_CLIENT_SECRET": "your-client-secret" } } } } ``` Refresh the MCP server list in Cascade (or restart Windsurf), then ask: > What regions can I deploy to on American Cloud? ## VS Code VS Code configures MCP servers for agent mode in `.vscode/mcp.json` (workspace) or your user profile. VS Code uses a `servers` key and supports prompted inputs, so you never write secrets into the file: ```json { "inputs": [ { "type": "promptString", "id": "ac-client-id", "description": "American Cloud API client ID" }, { "type": "promptString", "id": "ac-client-secret", "description": "American Cloud API client secret", "password": true } ], "servers": { "americancloud": { "type": "stdio", "command": "npx", "args": ["-y", "@americancloud/mcp"], "env": { "AMERICANCLOUD_API_CLIENT_ID": "${input:ac-client-id}", "AMERICANCLOUD_API_CLIENT_SECRET": "${input:ac-client-secret}" } } } } ``` VS Code prompts for both values the first time the server starts and stores them securely. Start the server from the MCP view (or when an agent first uses it), then test with the same regions question in Copilot's agent mode. ## Any other MCP client The server is a standard MCP stdio server. Whatever your client's configuration looks like, the three things it needs are: | Setting | Value | |---|---| | Command | `npx` | | Arguments | `-y @americancloud/mcp` | | Environment | `AMERICANCLOUD_API_CLIENT_ID`, `AMERICANCLOUD_API_CLIENT_SECRET` | Optional flags go after the package name in the arguments — for example `--services all` or `--allow-writes`. See the [overview](/docs/mcp/overview) for what they do. ## Enable resource management (optional) By default the server is read-only in every client. To enable create/update/delete tools, use a **read-write API key** and add `--allow-writes` to the arguments: ```json "args": ["-y", "@americancloud/mcp", "--allow-writes"] ``` Destructive operations are flagged, so clients that support confirmations will prompt you before running them. ## Next steps - [Things to try](/docs/mcp/use-cases) — prompt ideas from quick audits to full provisioning - [Overview](/docs/mcp/overview) — service groups, `--services` scoping, and safety details ## Things to try Once your client is [connected](/docs/mcp/overview), here's what the American Cloud MCP server is good at. Prompts below are starting points — adapt them to your account and phrasing. ## Explore and audit (read-only) These work out of the box, even with a read-only API key. They're the best way to build trust in the setup before enabling writes. **Take inventory:** > What's running in my account right now? List every VM with its region, size, IP, and power state. **Understand your spend:** > Walk through everything in my account and estimate what each resource costs per month. What's the biggest line item? **Security review:** > Audit my firewall rules and network ACLs. Is anything open to the whole internet that doesn't need to be? Which ports are exposed on each public IP? **Find waste:** > Are there any block storage volumes not attached to a VM, or reserved public IPs not assigned to anything? **Incident triage:** > I can't reach my app on port 443. Check the VM's power state, the firewall rules on its public IP, any port forwarding rules, and whether it's behind a load balancer with healthy members. **Snapshot hygiene:** > List all my snapshots with their creation dates. Which volumes have no recent snapshot? ## Price before you build (read-only) Cost estimates are tools too, so the assistant can compare options **before creating anything**: > What would a 3-node Kubernetes cluster with mid-size workers cost per month? > Compare the monthly cost of one large VM versus three small ones behind a load balancer. ## Provision and manage (requires `--allow-writes`) With a read-write key and the `--allow-writes` flag (see [overview](/docs/mcp/overview)), the assistant can build: **A development environment in one prompt:** > Create a small Ubuntu VM in us-west on an isolated network, use my SSH key, and open ports 22, 80, and 443. Show me the cost estimate first. **Pre-deploy safety net:** > Take a snapshot of every volume attached to my database VMs, named with today's date. **Database plus DNS:** > Set up PostgreSQL on a small VM, keep it listening on the private network only, then add an A record for api.example.com pointing at my load balancer's IP. **Routine operations:** > Reboot the staging VM and confirm it comes back up. > Resize the volume on my build server to 200 GB. Ask for the plan first. A prompt like *"tell me what you would do before doing it"* makes the assistant lay out each step — and clients prompt for confirmation on destructive operations regardless. ## Code and cloud together (coding agents) In a coding agent like [Claude Code](/docs/mcp/claude-code), the MCP server combines with your terminal — the assistant can provision infrastructure *and* use it in the same session: **Build and deploy:** > Create a VM for this project, open ports 22 and 80, then install nginx over SSH and deploy the site in ./dist. **Kubernetes workflow:** > Fetch the kubeconfig for my cluster and check whether all deployments are healthy. **Infrastructure as conversation:** > Stand up a staging copy of my production setup — same network layout, half the VM size — and give me a cost comparison when you're done. ## Tips for better results - **Scope the tool list.** If you only work with compute and DNS, set `--services compute,dns` — a smaller tool list helps the assistant pick the right tool faster. - **Ask for cost estimates first.** The assistant has pricing tools; make "estimate before create" part of your prompts until it's a habit. - **Start read-only.** Run a week of audits and triage with a read-only key before enabling writes. You'll learn what the assistant is good at with zero risk. - **Be specific about regions and sizes** when provisioning, or ask the assistant to list the options and recommend one. --- # Deploy with AI Deployment recipes and migration playbooks for AI assistants ## Overview Your AI assistant already writes your software. On American Cloud, it can deploy and operate it too. These pages are **recipes**: each one gives you a battle-tested prompt to paste into your assistant — Claude Code, Cursor, or any [MCP client](/docs/mcp/overview) — plus a step-by-step account of what the assistant will do with it. The assistant does the work through the [American Cloud MCP server](/docs/mcp/overview); you review and confirm. ## Before you start 1. Set up the MCP server for your client — [Claude Desktop](/docs/mcp/claude-desktop), [Claude Code](/docs/mcp/claude-code), [Cursor](/docs/mcp/cursor), [Codex](/docs/mcp/codex), or [others](/docs/mcp/other-clients). 2. Deployments create real resources, so you'll need a **read-write API key** and the `--allow-writes` flag — see [the overview](/docs/mcp/overview) for how both fit together. 3. For deploy workflows, a coding agent (Claude Code) is the strongest pairing: it combines American Cloud tools with a terminal, so it can provision a server *and* deploy to it in one conversation. Every recipe follows the same rule: **the assistant shows you a cost estimate before creating anything.** You always know the monthly price before a resource exists. ## Deployment recipes - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — from working code to a live URL with a domain and TLS - [Object storage](/docs/deploy-with-ai/object-storage) — S3-compatible storage for uploads, assets, backups, and archives - [Kubernetes](/docs/deploy-with-ai/kubernetes) — provision and scale clusters with MCP tools, operate workloads with kubectl - [Deploy a Docker Compose app](/docs/deploy-with-ai/docker-compose) — if it runs with `docker compose up`, it can run here - [Your own PaaS: Coolify](/docs/deploy-with-ai/coolify) — git-push deploys on a server you own, at a flat monthly price - [Self-host Supabase](/docs/deploy-with-ai/supabase) — the full Supabase stack on your own VM - [Scale out behind a load balancer](/docs/deploy-with-ai/load-balancer) — the "after your first VM" sequel - [Backups and restore drills](/docs/deploy-with-ai/backups) — take backups and actually prove they restore ## Migration playbooks Moving from another platform? The assistant inventories what you have, proposes the American Cloud equivalent with a cost estimate, and executes the move in phases — with a DNS cutover at the end, not a leap of faith at the start. - [Migrate from Vercel](/docs/deploy-with-ai/migrate-from-vercel) - [Migrate from AWS](/docs/deploy-with-ai/migrate-from-aws) - [Migrate from Heroku](/docs/deploy-with-ai/migrate-from-heroku) - [Migrate from DigitalOcean](/docs/deploy-with-ai/migrate-from-digitalocean) - [Migrate from Linode](/docs/deploy-with-ai/migrate-from-linode) - [Migrate from Render](/docs/deploy-with-ai/migrate-from-render) - [Migrate from Fly.io](/docs/deploy-with-ai/migrate-from-fly-io) - [Migrate from Netlify](/docs/deploy-with-ai/migrate-from-netlify) - [Move WordPress off shared hosting](/docs/deploy-with-ai/migrate-wordpress) ## Teach your agent the way here Add one file to your repository and any AI coding agent knows how to deploy that project to American Cloud — conventions, canonical flows, cost-estimate-first behavior included: - [The AGENTS.md drop-in](/docs/deploy-with-ai/agents-md) ## Looking for ideas first? [Things to try with the MCP server](/docs/mcp/use-cases) collects smaller prompts — audits, cost reviews, incident triage — that work with a read-only key and zero risk. ## Deploy a Next.js app You built a Next.js app in Claude Code, Cursor, or v0. It runs on `localhost`. Now you want it on a real server, on your own domain, with HTTPS — without learning Linux, nginx, or DNS first. This recipe hands the whole job to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant can pick a region, size a server, show you the cost, create the VM, open the right ports, install everything over SSH, point your domain at it, and turn on TLS — all from prompts you paste in. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But deploying a Next.js app also means running commands *on* the server: SSH in, install Node, build the app, configure a service. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so a single session can provision the VM and deploy to it without you switching tools. That's the setup this recipe assumes. Cursor and the other clients work too — you'll just run the SSH steps yourself when the assistant tells you to. Provisioning is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only, get comfortable, then switch the key when you're ready to build. ## Before you start - A working Next.js app in a local git repo (it runs with `next build` and `next start`). - A domain you control, with the ability to point its nameservers or DNS at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## The one prompt that does it Open your project in Claude Code and paste this, filling in the two placeholders. Read the cost estimate it shows you before approving anything. ```text I have a Next.js app in this repo. Deploy it to American Cloud on the domain {your-domain.com}. Plan it out first, then walk through it step by step: 1. List the available regions and Ubuntu images, and the VM packages. Recommend a small, low-cost size that can build a Next.js app. 2. Check whether I already have an SSH key registered. If not, create one for me and tell me where the private key is. 3. Show me a monthly cost estimate for the VM before creating anything. Wait for me to confirm. 4. Create a small Ubuntu VM with that SSH key, on an isolated network, and open inbound ports 22, 80, and 443. Wait until it's fully running. 5. Over SSH: install Node.js LTS and nginx. Clone or copy this repo to the server, run the production build with Next.js standalone output, and run the app as a systemd service that restarts on boot and on crash. 6. Configure nginx as a reverse proxy in front of the app on port 80. 7. Add a DNS A record pointing {your-domain.com} at the VM's public IP. 8. Once DNS resolves, provision a Let's Encrypt TLS certificate with certbot and switch nginx to HTTPS with auto-renewal. Confirm the site is live at https://{your-domain.com} when you're done. ``` ### What your assistant will do Grounded in real MCP tools, here's the sequence: 1. **Survey the options.** It calls `list_regions`, `list_images` (filtered to Ubuntu), and `list_vm_packages` to find a region near you, a current Ubuntu LTS image, and a small compute tier within its CPU/memory limits. 2. **Sort out the SSH key.** It calls `list_ssh_keys` to see what's already registered. If nothing fits, `create_ssh_key` generates a new pair — the private key is returned once and never stored, so your assistant saves it locally (for example to `~/.ssh/`) and sets the right permissions. It needs this key both to register on the VM and to SSH in afterward. 3. **Price it first.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image — and shows you the hourly and monthly numbers *before* creating anything. Nothing is billed yet. 4. **Create the server.** On your go-ahead, `create_vm` provisions a small Ubuntu VM. The same call carries `networkAccess` to open inbound ports 22 (SSH), 80 (HTTP), and 443 (HTTPS) on the network's public IP, and `keypairs` to install your SSH key. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` and it has a public IP. 5. **Set up the server over SSH.** Now in the terminal, it installs Node.js LTS and nginx, pulls your code onto the VM, and runs the production build. For Next.js it uses **standalone output** (`output: "standalone"` in `next.config`), which bundles only the files the server needs into `.next/standalone` — smaller, faster to copy, and easy to run with a plain `node server.js`. 6. **Make it a service.** It writes a `systemd` unit so the app starts on boot, restarts if it crashes, and runs on a local port (commonly 3000). 7. **Put nginx in front.** nginx listens on port 80 and reverse-proxies to the Next.js process, so the public ports you opened map to your app. 8. **Point the domain at it.** It calls `list_dns_zones` to see if your domain is already hosted. If not, `create_dns_zone` adds it (you'll then update your registrar's nameservers to American Cloud's, which the assistant can show you). Then `create_dns_record` adds an `A` record for the domain pointing at the VM's public IP. 9. **Turn on HTTPS.** Once DNS resolves to the VM, it runs certbot to obtain a Let's Encrypt certificate, reconfigures nginx for port 443, and enables automatic renewal. When it's done, you have a Next.js app served over HTTPS on your own domain, on a server you own and can SSH into. Tell the assistant to **explain each step before it runs it** if you want to follow along — *"narrate what you're about to do and why."* Destructive operations are flagged regardless, and clients that support confirmations will prompt you before anything irreversible. ## Follow-up: a one-prompt deploy command The first deploy is the hard part. Make every future deploy trivial by asking your assistant to script it: ```text Set up a deploy script in this repo that I can run to ship updates to the server. It should: push the latest committed code to the VM over SSH, run the production build there, and restart the systemd service. Add a "deploy" entry to package.json scripts that runs it. Document the one command I run from now on. ``` After this, shipping a change is *"run the deploy script"* — or just *"deploy the latest"* and the assistant runs it for you. ## Follow-up: add a database on the same server If your app needs a database, your assistant can install one directly on the VM over SSH: ```text My app needs PostgreSQL. Install it on the VM, create a database and user for this app, store the connection string in the app's environment file, and restart the service. Keep PostgreSQL listening only on localhost so it isn't exposed to the internet. ``` This keeps the database private to the server — nothing new is opened on the firewall, and only your app talks to it over `localhost`. ## Static site instead? If your Next.js app is fully static (`output: "export"`), the same recipe gets simpler: no Node process and no systemd service — nginx serves the exported files directly, so the smallest VM tier is plenty. Just tell the assistant your app uses static export and it adapts the plan. And if your app handles user uploads or large assets, pair the VM with [object storage](/docs/deploy-with-ai/object-storage) instead of filling the server's disk. ## Troubleshooting **The domain doesn't load right after the DNS record is added.** DNS changes take time to propagate — anywhere from a few minutes to a couple of hours, depending on your registrar and the record's TTL. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* certbot also needs DNS to resolve to the VM before it can issue a certificate, so the HTTPS step may have to wait for propagation. **The site is unreachable on port 80 or 443.** Ask your assistant to *"list the firewall rules on the VM's public IP and confirm 80 and 443 are open."* It can call `list_firewall_rules`, and add any missing rule with `create_firewall_rule`. Also have it check the VM is `STARTED` with `get_vm` and that both the app service and nginx are running on the server. **The build runs out of memory on a small VM.** Next.js builds can be memory-hungry. If the build is killed, ask your assistant to either *"add swap space on the VM and retry the build,"* or *"build the app locally and copy the standalone output to the server instead of building on the VM."* Both are one prompt each. **SSH connection refused.** Confirm port 22 is open (same `list_firewall_rules` check) and that the private key from the `create_ssh_key` step is the one your assistant is using. If the key was lost, your assistant can reset access with `reset_vm_password` or open a browser console session. ## Next steps - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, networking, and DNS - [Use American Cloud with Claude Code](/docs/mcp/claude-code) — the build-and-deploy client setup - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — uploads, assets, and backups for your app - [Migrate from Vercel](/docs/deploy-with-ai/migrate-from-vercel) — move an existing Next.js deployment - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — when one VM isn't enough - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your deploy conventions ## Object storage American Cloud object storage is **S3-compatible**, so anything that already speaks S3 — the AWS CLI, the AWS SDKs, `s3cmd`, `rclone`, your framework's upload library — works by pointing at a new endpoint. And there are **no egress fees**: you download your own data without paying per gigabyte to access it (see [why egress fees matter](/blog/egress-fees-explained)). That makes it a natural fit for AI-driven workflows. With the [American Cloud MCP server](/docs/mcp/overview) connected, you can ask your assistant to create a storage unit, hand you the connection details, and write the integration code for your stack — all from the same chat where you're building the app. This page is a recipe: copy a prompt, see exactly what your assistant does with it, then drop in working S3 code. ## What you'll need - The American Cloud MCP server connected to your assistant. If you haven't set it up yet, start with the [overview](/docs/mcp/overview), then your client guide: [Claude Code](/docs/mcp/claude-code), [Cursor](/docs/mcp/cursor), or [other clients](/docs/mcp/other-clients). - For the create steps below, a **read-write API key** plus the `--allow-writes` flag. Reading your usage and fetching connection details work with a read-only key. See [Safety](/docs/mcp/overview#safety-read-only-by-default). How the pieces fit: a **storage unit** holds your **buckets** and has its own S3 **access keys**. You create one unit, add buckets inside it, and use that unit's keys to connect any S3 client. Storage is metered by usage, so you're not sizing a disk up front. ## Create a storage unit and bucket Start a conversation and paste: > Create an object storage unit called \{app-name\}-prod, then add a bucket called uploads inside it. Show me the cost estimate first. **What your assistant will do:** 1. Call `get_cost_estimate_object_storage` to show the metered pricing before anything is created — object storage is billed by actual usage, so this is the per-GB rate and any minimum, not a fixed disk size. 2. Once you confirm, call `create_object_storage_unit` to provision the unit and return its identifier. 3. Call `create_object_storage_bucket` against that unit to create the `uploads` bucket. 4. Report back the unit and bucket so you can confirm they exist. Want a guardrail against runaway growth? Add a cap in the same breath: > Also set a 500 GB limit on that unit so it can't grow unbounded. The assistant uses `set_object_storage_quota` to apply the limit. Ask it to remove the cap later and it does the same in reverse. You can always take inventory of what you have: > List my object storage units with their current usage, and show the buckets in each one. This runs `list_object_storage_units` (with usage figures) and `list_object_storage_buckets` — both read-only, so they work even before you enable writes. ## Fetch your access keys and endpoint To connect any S3 client you need the unit's access key, secret, and endpoint. Ask: > Fetch the S3 access keys and connection details for my \{app-name\}-prod storage unit. The assistant calls `get_object_storage_keys` for the unit and returns the access key, secret key, and the S3 endpoint to use. The keys tool returns a **secret** — its tool description is labeled sensitive for exactly this reason. Treat the secret like any other credential: don't paste it into shared chats or commit it to a repo. Put it in an environment variable or a secrets manager, and rotate it if it's ever exposed. For the steps below, store what the assistant returns as environment variables. Use the **endpoint your assistant reports** for `S3_ENDPOINT` (it includes the `https://` scheme): ```sh export S3_ENDPOINT="https://" export S3_ACCESS_KEY="" export S3_SECRET_KEY="" export S3_BUCKET="uploads" ``` ## Wire an app to it Object storage is S3-compatible, so every integration below is standard S3 code with two changes: a custom endpoint and your American Cloud credentials. Pick your tool. ### Node.js with the AWS SDK v3 Install the S3 client: ```sh npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner ``` Upload a file and generate a presigned download URL. The credentials and endpoint come from the environment variables you set above — `forcePathStyle: true` is the one S3-compatibility detail to remember: ```js import { readFile } from "node:fs/promises"; import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const s3 = new S3Client({ endpoint: process.env.S3_ENDPOINT, region: "us-east-1", // any value; required by the SDK but unused forcePathStyle: true, credentials: { accessKeyId: process.env.S3_ACCESS_KEY, secretAccessKey: process.env.S3_SECRET_KEY, }, }); const Bucket = process.env.S3_BUCKET; // Upload a file await s3.send( new PutObjectCommand({ Bucket, Key: "avatars/user-123.png", Body: await readFile("./user-123.png"), ContentType: "image/png", }), ); // Generate a presigned URL that lets someone download it for 1 hour const url = await getSignedUrl( s3, new GetObjectCommand({ Bucket, Key: "avatars/user-123.png" }), { expiresIn: 3600 }, ); console.log("Download link:", url); ``` Presigned URLs let you share a private object temporarily without exposing your keys — ideal for user downloads, email attachments, or time-limited access. For a longer walkthrough, see [uploading files to object storage with Node.js](/docs/tutorials/using-nodejs-to-upload-files-to-a2-storage). ### AWS CLI The standard `aws` CLI works against object storage with the `--endpoint-url` flag. Set credentials however you normally would (`aws configure`, env vars, or a named profile): ```sh export AWS_ACCESS_KEY_ID="$S3_ACCESS_KEY" export AWS_SECRET_ACCESS_KEY="$S3_SECRET_KEY" # List objects in a bucket aws s3 ls "s3://$S3_BUCKET/" --endpoint-url "$S3_ENDPOINT" # Upload a file aws s3 cp ./report.pdf "s3://$S3_BUCKET/reports/report.pdf" --endpoint-url "$S3_ENDPOINT" # Sync a local directory up aws s3 sync ./public "s3://$S3_BUCKET/static/" --endpoint-url "$S3_ENDPOINT" ``` Prefer a dedicated tool? The [s3cmd guide](/docs/tutorials/s3cmd-simple-storage-service-command-line-tool-and) walks through the configuration wizard end to end and every common bucket and object command. ### rclone for bulk sync and migration `rclone` is the fastest way to move large datasets, and it talks S3 on both ends — so it can copy directly from another S3 provider into American Cloud. Add a remote (`rclone config`, provider type `Other`/S3-compatible) or write it inline: ```sh # An American Cloud remote, configured inline rclone copy ./build americancloud:$S3_BUCKET/releases/v2 --progress # S3-to-S3 migration: copy straight from another provider's bucket rclone copy oldprovider:legacy-bucket americancloud:$S3_BUCKET --progress --transfers 16 ``` Because there are no egress fees on the American Cloud side, pulling data in is free — only the source provider's egress applies. For a full provider switch, pair this with [migrate from AWS](/docs/deploy-with-ai/migrate-from-aws). ### Let your assistant write the integration You don't have to translate any of this by hand. If you're working in a coding agent like [Claude Code](/docs/mcp/claude-code), tell it your stack and the env var names you used: > I've stored my object storage credentials in S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, and S3_BUCKET. Add an upload route to my Next.js app that stores user avatars in object storage and returns a presigned URL. Read the values from the environment — don't hardcode the secret. The assistant has both the connection details (from `get_object_storage_keys`) and your codebase, so it can write the S3 client, the route handler, and the env wiring for your framework, then explain what it did. Ask it to use the env vars rather than inlining the secret. ## Common patterns A few things developers reach for object storage to do, and the prompts to set them up. ### User uploads and static assets Serve user-generated content and your app's static files straight from a bucket: > My app needs somewhere to put user-uploaded images. Create an object storage unit and an "uploads" bucket, fetch the keys, and add an upload helper to my project that returns a presigned URL for each file. ### Off-site backups from a VM Push nightly database dumps or upload directories off your server and into a bucket. In a coding agent that can reach your VM over SSH: > Set up a nightly cron job on my VM that tars /var/www/uploads and pushes it to my object storage bucket under backups/, keeping the last 14 days. Use the AWS CLI with my endpoint and rotate out anything older. **What your assistant will do:** 1. Confirm (or create, with `create_object_storage_bucket`) a bucket to hold the backups. 2. Fetch the keys with `get_object_storage_keys` so the VM can authenticate. 3. Over SSH, install the AWS CLI if needed, write a backup script that archives the directory and uploads it with `aws s3 cp --endpoint-url`, and prune objects older than 14 days. 4. Add a `cron` entry to run it nightly and confirm the schedule. Zero egress fees matter most here: restoring a backup means downloading it, and that download is free. ### Build artifacts and data archives Hosting build outputs, release bundles, or long-term archives is the same shape — a bucket plus an upload step in your pipeline: > Add a step to my deploy script that uploads the contents of ./dist to my object storage bucket under releases/$(git rev-parse --short HEAD)/, so every build is archived. ## Next steps - [Object storage overview](/docs/object-storage/a2-object-storage) — units, buckets, presigned share links, and the dashboard. - [s3cmd guide](/docs/tutorials/s3cmd-simple-storage-service-command-line-tool-and) — the full CLI reference for buckets and objects. - [Upload files with Node.js](/docs/tutorials/using-nodejs-to-upload-files-to-a2-storage) — a longer SDK walkthrough. - [Migrate from AWS](/docs/deploy-with-ai/migrate-from-aws) — move existing workloads, including S3 buckets, with your assistant. - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) and [run Kubernetes](/docs/deploy-with-ai/kubernetes) — the rest of the deploy-with-AI recipes. - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, networking, and storage. ## Run Kubernetes Kubernetes has two jobs that usually live in two different places: standing up the cluster (infrastructure) and running things on it (workloads). With the American Cloud [MCP server](/docs/mcp/overview), an AI assistant covers both — and in a coding agent like [Claude Code](/docs/mcp/claude-code), both happen in one conversation. This recipe shows the full loop: create a cluster from a prompt with the cost shown up front, connect `kubectl`, deploy an app, triage what's running, and add capacity when traffic grows. ## The two layers It helps to keep these straight, because the assistant works at both and switches between them in a single session: - **Infrastructure layer — MCP tools.** Creating the cluster, picking a node size and region, previewing cost, fetching the kubeconfig, and scaling worker capacity all happen through the American Cloud MCP server. These are American Cloud API calls, not `kubectl`. - **Workload layer — your terminal.** Once the kubeconfig is in place, the assistant uses `kubectl` in your shell to apply manifests, watch rollouts, read logs, and debug pods. This is ordinary Kubernetes — nothing American Cloud-specific. In a coding agent the assistant can author your manifests, create the cluster that runs them, and then apply them — all without you switching windows. The infrastructure layer needs the MCP server connected. The workload layer needs a coding agent that can run shell commands (like Claude Code) plus `kubectl` installed locally. A chat-only client can do everything in the infrastructure layer — create, scale, fetch the kubeconfig — but can't run `kubectl` for you. ## Before you start - The MCP server connected to your client — see [overview](/docs/mcp/overview). - For the create and scale prompts below, a **read-write API key** and the `--allow-writes` flag. Read tools — listing clusters, cost estimates, fetching the kubeconfig — work with a read-only key. - For the deploy and operate prompts, a coding agent that can run shell commands, and `kubectl` installed. See [Kubernetes getting started](/docs/kubernetes/getting-started) for install commands. ## Provision a cluster Lead with the cost. The MCP server has a Kubernetes cost-estimate tool that takes the same inputs as the create tool, so the assistant can price a configuration before it provisions anything. > Create a small Kubernetes cluster on American Cloud — show me the cost estimate first. **What your assistant will do:** 1. Call `list_kubernetes_packages` for node sizing tiers, `list_regions` for regions, and `list_kubernetes_versions` for available Kubernetes versions, then propose a configuration (a small worker package, a sensible region, the latest version). 2. Call `get_cost_estimate_kubernetes` with that configuration and show you the monthly cost — **before creating anything**. 3. Wait for your go-ahead, then call `create_kubernetes_cluster` with the name, package, region, version, control-node count, and worker-node count. (Three or more control nodes give you a highly available control plane; one is fine for dev. Pass an SSH key from `list_ssh_keys` if you want node access.) 4. Poll `get_kubernetes_cluster` until status goes from `CREATING` to `RUNNING` — provisioning takes a few minutes. If you have an opinion on size, region, or version, say so in the prompt (*"3 control nodes, mid-size workers, in us-west"*). If you don't, let the assistant list the options and recommend one, then confirm. ## Connect and deploy This is where the coding agent earns its keep: it fetches the kubeconfig through the MCP server and then deploys through your terminal. > Fetch the kubeconfig for that cluster and deploy this app to it. **What your assistant will do:** 1. Call `get_kubernetes_cluster_config` to retrieve the cluster's kubeconfig (YAML) and write it where `kubectl` can find it — typically a file it points `KUBECONFIG` at. 2. Run `kubectl get nodes` to confirm the control and worker nodes are `Ready`. 3. Read your project to understand what it is (a web service, a worker, what port it listens on, whether it has a container image or needs one built). 4. Write the Kubernetes manifests — a Deployment, a Service, and an Ingress or a `Service` of type `LoadBalancer` to expose it — and `kubectl apply` them. 5. Watch the rollout with `kubectl rollout status` and report when the pods are healthy and the app is reachable. The kubeconfig grants full access to your cluster. The tool that returns it is read-only in the MCP sense — it doesn't change your infrastructure — but the credentials it hands back are sensitive. Treat the file like any other secret: don't commit it, and don't paste it into a shared channel. Ask your assistant to write it to a path outside your repo (or one your `.gitignore` already covers). If your app needs a database, run PostgreSQL on its own American Cloud VM (ask the assistant to provision one and point a connection string at it), or deploy it inside the cluster from a manifest with a persistent volume. Either way, the assistant can wire it up in the same session. To get the public address of your exposed service once the ingress controller assigns it, the assistant reads it from `kubectl` — see [accessing your cluster via public IP](/docs/kubernetes/accessing-your-kubernetes-cluster-via-public-ip) for which IP is which. ## Operate and triage Day-two work is mostly `kubectl`, and this is exactly the kind of repetitive inspection an assistant is good at. No new infrastructure tools here — it's reading cluster state through your terminal. > Are all my deployments healthy? **What your assistant will do:** 1. Run `kubectl get deployments -A` and `kubectl get pods -A` to survey every namespace. 2. Flag anything not at full ready replicas, any pods in `CrashLoopBackOff`, `Pending`, or `ImagePullBackOff`, and any recent restarts. 3. Summarize the state in plain English and offer to dig into anything that looks off. When something is wrong, hand it the symptom: > Why is the api pod crashlooping? **What your assistant will do:** 1. Run `kubectl describe pod` on the failing pod and read the events (failed image pull, OOMKilled, failing readiness probe, unschedulable). 2. Pull the logs with `kubectl logs --previous` to see why the last container exited. 3. Explain the root cause and propose a fix — a corrected environment variable, a higher memory request, a fixed probe path, a missing secret — and, with your okay, edit the manifest and re-apply it. This loop — observe, hypothesize, fix, re-apply — is the same one you'd run by hand, just narrated and faster. ## Scale when traffic grows Adding capacity is back in the infrastructure layer: the MCP server changes the worker count on the managed cluster directly. > Traffic is growing — add worker capacity to the cluster. **What your assistant will do:** 1. Call `get_kubernetes_cluster` (with `details=true`) to read the current worker count and node utilization. 2. Propose a new total worker count, or suggest turning on autoscaling so the cluster adds and removes workers with load. 3. Call `scale_kubernetes_cluster` — either with a fixed `workerNodes` total, or with autoscaling enabled and a `minWorkers`/`maxWorkers` range. 4. Confirm the new nodes register by running `kubectl get nodes` once they come up. The scale tool sets the **total** worker count, not the number to add. If you have four workers and want one more, the target is five. The assistant reads the current count first so it gets this right — but it's worth knowing if you check the result yourself. The same cluster can also be paused, upgraded to a newer Kubernetes version, or removed entirely through the MCP server when you ask. Upgrades and deletes are flagged so your client can prompt before they run. ## When to choose Kubernetes vs a single VM Kubernetes is the right tool when you have several services that scale independently, want rolling deploys and self-healing pods, or already think in containers and manifests. The assistant makes the cluster cheap to stand up and easy to operate — but the cluster itself is still more moving parts than some workloads need. If you're shipping a single app — a Next.js site, an API, a small service — a single VM is often the better fit: less to run, less to reason about, lower cost. The assistant can provision and deploy to one just as fluently. See [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) for that path. Pick the one that matches the shape of your workload, not the one that sounds more impressive. ## Next steps - [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — the single-VM path for one app - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — persistent storage for uploads and backups - [Migrate from AWS with your AI assistant](/docs/deploy-with-ai/migrate-from-aws) — move an existing workload over - [Give your agent an AGENTS.md](/docs/deploy-with-ai/agents-md) — make the assistant follow your project's conventions - [Kubernetes getting started](/docs/kubernetes/getting-started) — the same workflow from the American Cloud interface - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across every service ## Deploy a Docker Compose app If it runs with `docker compose up` on your laptop, it can run on a server. A `docker-compose.yml` is the most universal deploy shape there is — a web service, a worker, a database, a cache, all wired together — and it moves to American Cloud almost unchanged. This recipe hands the whole job to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant reads your compose file to understand what it's running, sizes a server to match, shows you the cost, creates the VM with the right ports open, installs Docker over SSH, brings the stack up, and puts it on your domain with HTTPS — from prompts you paste in. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But deploying a compose stack also means running commands *on* the server: SSH in, install Docker, pull images, run `docker compose up`. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so a single session can provision the VM and deploy to it without switching tools. That's the setup this recipe assumes. [Cursor](/docs/mcp/cursor) and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when the assistant tells you to. Provisioning is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only, get comfortable, then switch the key when you're ready to build. ## Before you start - A working `docker-compose.yml` in a local git repo (the stack comes up with `docker compose up` on your machine). - A list of which secrets your services need — database passwords, API keys. You'll hand the assistant the variable *names*; the *values* go straight onto the server. - A domain you control, with the ability to point its nameservers or DNS at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## The one prompt that does it Open your project in Claude Code and paste this, filling in the two placeholders. Read the cost estimate it shows you before approving anything. ```text I have a Docker Compose app in this repo. Deploy it to American Cloud on the domain {your-domain.com}. Plan it out first, then walk through it step by step: 1. Read docker-compose.yml to understand the services, the ports they expose, the named volumes, and whether the stack includes its own reverse proxy (Traefik, Caddy, nginx). Tell me what you found. 2. List the available regions and Ubuntu images, and the VM packages. Recommend a size with enough CPU, memory, and disk to run all the services in my compose file comfortably. 3. Check whether I already have an SSH key registered. If not, create one for me and tell me where the private key is. 4. Show me a monthly cost estimate for the VM before creating anything. Wait for me to confirm. 5. Create an Ubuntu VM with that SSH key, on an isolated network, and open inbound ports 22, 80, and 443. Wait until it's fully running. 6. Over SSH: install Docker Engine and the compose plugin. Clone or copy this repo to the server. 7. Create the server-side environment file. I'll give you the variable names now and paste the secret values directly on the server — do not put real secret values in this chat. 8. Bring the stack up with docker compose up -d and confirm every container is healthy. 9. If my stack does NOT bring its own proxy, install nginx and reverse-proxy it in front of the web service on port 80. If it DOES bring its own proxy, point ports 80 and 443 straight at it instead. 10. Add a DNS A record pointing {your-domain.com} at the VM's public IP. 11. Once DNS resolves, set up HTTPS: run certbot for a Let's Encrypt certificate if nginx is in front, or let the stack's own proxy handle ACME if it has one. Confirm the site is live at https://{your-domain.com} when you're done. ``` ### What your assistant will do Grounded in real MCP tools, here's the sequence: 1. **Read the compose file.** It opens `docker-compose.yml` in your repo and works out the shape of the stack: which service faces the web and on what port, which services are internal-only (databases, caches, workers), what named volumes hold data, and whether the stack already ships a reverse proxy. That last point decides how HTTPS gets handled at the end. 2. **Survey the options.** It calls `list_regions`, `list_images` (filtered to Ubuntu), and `list_vm_packages` to find a region near you, a current Ubuntu LTS image, and a compute tier with enough headroom for everything in the compose file at once — a multi-service stack needs more memory and disk than a single app. 3. **Sort out the SSH key.** It calls `list_ssh_keys` to see what's already registered. If nothing fits, `create_ssh_key` generates a new pair — the private key is returned once and never stored, so your assistant saves it locally (for example to `~/.ssh/`) and sets the right permissions. It needs this key both to register on the VM and to SSH in afterward. 4. **Price it first.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image — and shows you the hourly and monthly numbers *before* creating anything. Nothing is billed yet. 5. **Create the server.** On your go-ahead, `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess.inboundPorts` to open 22 (SSH), 80 (HTTP), and 443 (HTTPS), and `keypairs` to install your SSH key. Opening ports through `create_vm` sets up the firewall rule *and* the port forwarding together, so the ports are actually reachable — a firewall rule on its own would not be. The VM provisions asynchronously (status `CREATING` → `STARTED`), so the assistant polls `get_vm` until it's `STARTED` with a public IP. 6. **Install Docker.** Now in the terminal, it installs Docker Engine and the compose plugin on the VM, then clones or copies your repo onto the server. 7. **Write the server-side `.env`.** Your compose file references secrets by name; the assistant creates the environment file *on the server* and you paste the real values there. The variable names can appear in chat — the values never need to. This keeps credentials off your transcript and out of the repo. 8. **Bring the stack up.** It runs `docker compose up -d` on the server and checks that each container reaches a healthy state. Internal services (your database, cache, queue) talk to each other over the private compose network and are never exposed on the public IP — only the web port is. 9. **Handle the front door.** If your compose stack *doesn't* include its own proxy, the assistant installs nginx, which listens on port 80 and reverse-proxies to the web service's published port. If your stack *does* bring its own proxy (Traefik, Caddy, an nginx service), there's no second proxy — ports 80 and 443 route straight to it. 10. **Point the domain at it.** It calls `list_dns_zones` to see if your domain is already hosted. If not, `create_dns_zone` adds it (you'll then point your registrar's nameservers at American Cloud, which the assistant can show you). Then `create_dns_record` adds an `A` record for the domain pointing at the VM's public IP. 11. **Turn on HTTPS.** Once DNS resolves to the VM, it either runs certbot to obtain a Let's Encrypt certificate and reconfigures nginx for port 443 with auto-renewal, or — if your stack's own proxy speaks ACME — lets that proxy request and renew the certificate itself. When it's done, you have your whole compose stack running over HTTPS on your own domain, on a server you own and can SSH into. Tell the assistant to **explain each step before it runs it** if you want to follow along — *"narrate what you're about to do and why."* Destructive operations are flagged regardless, and clients that support confirmations will prompt you before anything irreversible. ## Follow-up: redeploy after a change Once it's live, shipping an update is one prompt: ```text I pushed new code. Redeploy the stack on the VM: SSH in, git pull the latest, run docker compose pull and docker compose build for any changed services, then docker compose up -d to recreate them. Confirm everything is healthy and the site still loads. ``` Ask the assistant to save this as a deploy script in the repo and every future update becomes *"run the deploy script"* — or just *"redeploy the latest."* ## Follow-up: triage a misbehaving container When something's wrong, describe the symptom and let the assistant investigate over SSH: ```text The api container keeps restarting. SSH into the VM and figure out why: check docker compose ps for its state and restart count, then read the recent logs with docker compose logs for that service. Tell me what's failing and propose a fix before changing anything. ``` The assistant reads the actual container state and logs from the server, so you get a diagnosis grounded in what's really happening rather than a guess. ## Your data lives on the VM disk Named volumes — your database files, uploaded content, anything a service writes to a mounted volume — live on the VM's disk. They survive `docker compose down` and restarts, but they're tied to that one server. Two things to set up early: - **Snapshots and offsite dumps** for disaster recovery. See [backups with your AI assistant](/docs/deploy-with-ai/backups) — ask it to snapshot the VM before risky changes, and to set up a nightly job that dumps your database to [object storage](/docs/deploy-with-ai/object-storage) so a copy lives off the server. - **App file storage** that you don't want filling the VM disk — user uploads, generated assets, large artifacts — belongs in [object storage](/docs/deploy-with-ai/object-storage), with your service writing to it instead of a local volume. ## Troubleshooting **Port 80 is already taken on the VM.** If your compose stack publishes a service on port 80 *and* you also asked for an nginx proxy, they collide. Ask your assistant to *"check what's bound to port 80 on the VM and pick one front door — either nginx proxying to the stack, or the stack's web service directly."* You only want one thing listening on 80. **A container can't reach another service.** Inside a compose network, services find each other by their *service name*, not `localhost`. If your app connects to `localhost:5432` for a database that's a separate compose service, it won't resolve. Ask the assistant to *"check the compose service names and make sure each service connects to the others by service name, not localhost."* **The site is unreachable on port 80 or 443.** Ask your assistant to *"list the firewall rules on the VM's public IP and confirm 80 and 443 are open."* It can call `list_firewall_rules` and check `list_port_forwarding_rules` — a port needs *both* a firewall rule (`create_firewall_rule`) and forwarding (`create_port_forwarding_rule`), or static NAT (`enable_static_nat`), to be reachable. Have it also confirm the VM is `STARTED` with `get_vm` and that the containers are healthy. **The disk is filling up.** Pulled images, stopped containers, and dangling build layers accumulate fast. Ask your assistant to *"SSH in and run docker system prune to reclaim space from unused images and containers,"* and if it keeps recurring, *"resize the VM's disk with `resize_vm_disk`."* **The domain doesn't load right after the DNS record is added.** DNS changes take time to propagate — minutes to a couple of hours, depending on your registrar and the record's TTL. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* certbot (and any ACME proxy) needs DNS pointing at the VM before it can issue a certificate, so the HTTPS step may have to wait for propagation. ## Next steps - [Scale out with a load balancer](/docs/deploy-with-ai/load-balancer) — run the stack on more than one VM behind a single IP - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — when one compose host isn't enough - [Backups with your AI assistant](/docs/deploy-with-ai/backups) — snapshots and offsite dumps for your volumes - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — uploads, assets, and backup targets - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your deploy conventions ## Run Coolify You like the platform-as-a-service experience: `git push` and it deploys, preview environments per branch, one-click databases and services, TLS handled for you. You'd just rather not pay per seat, per build, and per gigabyte of bandwidth for it — especially if you run a lot of small apps. [Coolify](https://coolify.io) gives you that experience on a server you own. It's an open-source, self-hostable PaaS: connect a git repo and it builds and deploys, spins up preview environments, manages the databases your apps need, and handles HTTPS. You run it on one virtual machine and pay one flat VM bill, no matter how many apps and team members you put on it. That's a strong fit for agencies and developers juggling many projects. This recipe hands the setup to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant can size a server, show you the cost, create the VM with the right ports open, install Coolify over SSH, and point a domain at the dashboard — all from prompts you paste in. After that, your day-to-day deploys live in Coolify's own UI. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But installing Coolify also means running its installer *on* the server over SSH. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so a single session can provision the VM and install Coolify on it without you switching tools. That's the setup this recipe assumes. [Cursor](/docs/mcp/cursor) and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH step yourself when the assistant tells you to. Provisioning is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only, get comfortable, then switch the key when you're ready to build. ## Before you start - A domain you control, with the ability to point its DNS at American Cloud (for a tidy dashboard URL with HTTPS — optional, but recommended). - The MCP server connected to your assistant with a read-write key and `--allow-writes`. - A few minutes after the VM boots — Coolify's installer pulls Docker and its own containers, so the first run isn't instant. Coolify's own [installation requirements](https://coolify.io/docs/) call for a fresh Linux server with root or sudo SSH access; a plain Ubuntu VM is exactly that. ## The one prompt that does it Open Claude Code and paste this, filling in the domain placeholder. Read the cost estimate it shows you before approving anything. ```text I want to self-host Coolify on American Cloud so I have my own deploy platform. Plan it out first, then walk through it step by step: 1. List the available regions and Ubuntu images, and the VM packages. Recommend a size that comfortably runs Coolify plus a few small apps. Coolify's docs suggest at least 2 CPU and 2 GB of RAM for a single server; give it some headroom. 2. Check whether I already have an SSH key registered. If not, create one for me and tell me where the private key is. 3. Show me a monthly cost estimate for the VM before creating anything. Wait for me to confirm. 4. Create an Ubuntu VM with that SSH key, on an isolated network, and open inbound ports 22, 80, 443, and Coolify's dashboard port 8000. Wait until it's fully running and has a public IP. 5. Over SSH, run Coolify's official install script as root. Wait for it to finish pulling Docker and bringing up the Coolify containers. 6. Add a DNS A record pointing coolify.{your-domain.com} at the VM's public IP. Then tell me the dashboard URL to open so I can finish onboarding in Coolify itself. ``` ### What your assistant will do Grounded in real MCP tools, here's the sequence: 1. **Survey the options.** It calls `list_regions`, `list_images` (filtered to Ubuntu), and `list_vm_packages` to find a region near you, a current Ubuntu LTS image, and a compute tier sized for Coolify. The [marketplace guide](/docs/marketplace/deploying-a-coolify-instance) notes that **2 vCPU / 2 GB memory / 50 GB disk** is a sensible starting point for a single-server install; the assistant picks a tier at or above that. 2. **Sort out the SSH key.** It calls `list_ssh_keys` to see what's already registered. If nothing fits, `create_ssh_key` generates a new pair — the private key is returned once and never stored, so your assistant saves it locally (for example to `~/.ssh/`) and sets the right permissions. It needs this key both to register on the VM and to SSH in to run the installer. 3. **Price it first.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image, and shows you the hourly and monthly numbers *before* creating anything. Nothing is billed yet. This is one flat VM cost — Coolify doesn't add per-app or per-seat charges on top. 4. **Create the server.** On your go-ahead, `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess.inboundPorts` to open inbound ports **22** (SSH), **80** (HTTP), **443** (HTTPS), and **8000** (Coolify's dashboard) on the network's public IP, and `keypairs` to install your SSH key. Opening a port through `networkAccess` sets up the firewall rule *and* the port forwarding together, so the ports are actually reachable — not just allowed. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` and it has a public IP. 5. **Install Coolify over SSH.** Now in the terminal, the assistant SSHes in with your key and runs Coolify's official install script as root. The script installs Docker if it's missing and brings up Coolify's own containers. Coolify — not American Cloud — manages everything from here: the apps you deploy, the databases those apps need, build pipelines, and TLS for your app domains. 6. **Point a domain at the dashboard.** It calls `list_dns_zones` to see if your domain is already hosted. If not, `create_dns_zone` adds it (you'll then update your registrar's nameservers to American Cloud's, which the assistant can show you). Then `create_dns_record` adds an `A` record for `coolify.\{your-domain.com\}` pointing at the VM's public IP. Port **8000** is where Coolify serves its dashboard on a fresh install (per Coolify's own docs). Once you attach a domain inside Coolify, it can serve the dashboard over 80/443 on that domain instead, but you need 8000 open to reach it for the very first login. When it's done, the assistant hands you the dashboard URL. The first time you open it you'll register your Coolify admin account and run Coolify's short onboarding — pick **This Machine** as the server when prompted, since Coolify is running on the VM you just created. From there you connect git repos and start deploying. Tell the assistant to **explain each step before it runs it** if you want to follow along — *"narrate what you're about to do and why."* Destructive operations are flagged regardless, and clients that support confirmations will prompt you before anything irreversible. ## Prefer the dashboard? Use the marketplace image If you'd rather not run an installer at all, American Cloud's marketplace ships a one-click Coolify image you create from the console — same result, no SSH. The step-by-step is in [Deploying a Coolify instance](/docs/marketplace/deploying-a-coolify-instance). Use whichever path you prefer; the MCP path in this recipe is the one your AI assistant can drive end to end. ## After setup: deploys in Coolify, infrastructure with your assistant Once Coolify is up, your everyday work happens *inside Coolify*: add a project, connect a repository, and push to deploy. Preview environments, environment variables, the databases your apps depend on, and per-app TLS are all Coolify features now. Your assistant and the MCP server stay useful for the layer underneath — the server Coolify runs on: - **Scale the VM as you add apps.** More projects means more memory and CPU. The assistant can resize in place with `scale_vm`, no rebuild. - **Snapshot before you upgrade Coolify.** Take a backup of the VM before a Coolify version bump so you can roll back if something misbehaves — see [Backups and snapshots with your AI assistant](/docs/deploy-with-ai/backups). - **DNS for each new app.** When you add an app on its own domain, ask the assistant to add the DNS record pointing it at the same VM; Coolify routes the request to the right app. ### Follow-up: "Coolify says it's low on resources" When Coolify warns it's running out of headroom, you don't have to guess at a new size: ```text Coolify says it's low on resources. Check the VM's CPU and memory usage over the last 24 hours, tell me how close it's running to its limits, and if it's tight, recommend a larger size and scale it up. Show me the new monthly cost before you make the change. ``` The assistant calls `get_vm_metrics` to read the last day of CPU, memory, network, and disk usage, reasons about how much headroom is left, and — with your go-ahead — uses `scale_vm` to raise the vCPU and memory. It can show the updated cost with `get_cost_estimate_vm` first so there are no surprises. ## Troubleshooting **The dashboard doesn't load on port 8000.** Ask your assistant to *"list the firewall rules on the VM's public IP and confirm port 8000 is open."* It can check with `list_firewall_rules`. Note that a firewall rule by itself does **not** make a port reachable — the traffic also needs a path to the VM. The `create_vm` step opens 8000 the right way (firewall *and* port forwarding together). If you ever add a port afterward, open it with **both** `create_firewall_rule` and `create_port_forwarding_rule` (or map the IP straight to the VM with `enable_static_nat`); a lone firewall rule will look open but stay unreachable. **The Coolify install is still finishing.** The installer pulls Docker and several containers on first run, so the dashboard isn't reachable until it completes. Ask the assistant to *"SSH in and check whether Coolify's containers are up yet"* before assuming something's wrong. **The dashboard subdomain doesn't resolve yet.** DNS changes take time to propagate — from a few minutes to a couple of hours, depending on your registrar and the record's TTL. Ask your assistant to *"check what coolify.\{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* In the meantime you can reach the dashboard at the VM's public IP on port 8000. **SSH connection refused.** Confirm port 22 is open (the same `list_firewall_rules` check) and that the private key from the `create_ssh_key` step is the one your assistant is using. If the key was lost, your assistant can reset access with `reset_vm_password` or open a browser console session with `create_vm_console`. ## Next steps - [Run apps with Docker Compose](/docs/deploy-with-ai/docker-compose) — if you'd rather drive Compose directly instead of through a PaaS layer - [Backups and snapshots with your AI assistant](/docs/deploy-with-ai/backups) — snapshot the VM before Coolify upgrades, and restore if needed - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your deploy conventions - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, networking, and DNS ## Self-host Supabase A huge share of AI-built apps run on Supabase. It's the default Postgres-plus-auth-plus-storage backend that coding agents reach for, and the hosted cloud version is the fastest way to start. But as a project grows, three things start to matter: predictable cost at scale, your data living on a server you control, and no automatic project pausing on idle. Self-hosting gives you all three. The catch has always been the Linux work — provisioning a server, running Supabase's Docker stack, generating secrets, putting a reverse proxy and TLS in front. This recipe hands that work to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant sizes a server, shows you the cost, creates the VM with the right ports open, and then does the whole server setup over SSH. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But self-hosting Supabase also means running commands *on* the server: SSH in, install Docker, pull Supabase's self-hosting compose files, generate secrets, bring the stack up. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so one session can provision the VM and configure it without you switching tools. That's the setup this recipe assumes. [Cursor](/docs/mcp/cursor) and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when the assistant tells you to. Provisioning is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only, get comfortable, then switch the key when you're ready to build. ## Before you start - A domain you control, with the ability to point its DNS at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. - Decide where your app lives. Supabase is the backend; your app (the frontend or API that talks to it) can live anywhere — see [deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) for putting it in front. Prefer a point-and-click path? American Cloud has a dashboard-based Supabase install in the marketplace — see the [Supabase marketplace guide](/docs/marketplace/supabase). This page is the AI-driven, full-control alternative: a plain Ubuntu VM plus Supabase's own official self-hosting setup, all driven from your assistant. ## Sizing the server Supabase's self-hosted stack is a set of Docker containers — its own Postgres database, the API gateway, auth, storage, the Studio dashboard, and supporting services — all running together with `docker compose`. That means you want a VM with enough memory to hold the whole stack comfortably, not a bare minimum box. Don't guess. Ask your assistant to read Supabase's own published self-hosting requirements and map them onto a VM size, with a cost estimate first: ```text I want to self-host Supabase on American Cloud. Look up Supabase's official self-hosting requirements for running their full Docker compose stack, then: 1. List the available regions and Ubuntu LTS images, and the VM packages. 2. Recommend a VM size that meets Supabase's stated requirements for the self-hosted stack, with some headroom for Docker and my data. 3. Show me the monthly cost estimate for that size before creating anything, and wait for me to confirm. ``` ### What your assistant will do 1. **Survey the options.** It calls `list_regions`, `list_images` (filtered to Ubuntu LTS), and `list_vm_packages` to find a region near your users and a compute tier whose CPU and memory limits cover Supabase's stated requirements for the self-hosted stack. 2. **Price it first.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image, and shows you the hourly and monthly numbers *before* creating anything. Nothing is billed until you approve. Size to Supabase's own published guidance, plus headroom — the stack runs more comfortably when it isn't memory-starved, and you can always [resize it later](#day-2-running-it) as your data grows. ## Create the server On your go-ahead, the assistant provisions the VM. The important detail here is **which ports it opens**, and it opens only what Supabase needs to be reachable from the public internet. ```text Create a small Ubuntu VM for Supabase with the size we agreed on. Put it on an isolated network, register my SSH key, and open inbound ports 22 (SSH) and 443 (HTTPS) only. Wait until it's fully running and report the public IP. ``` ### What your assistant will do 1. **Sort out the SSH key.** It calls `list_ssh_keys` to see what's registered. If nothing fits, `create_ssh_key` generates a new pair — the private key is returned once and never stored, so the assistant saves it locally (for example to `~/.ssh/`) with correct permissions. It needs this key both to register on the VM and to SSH in afterward. 2. **Create the VM with the right ports open.** `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess.inboundPorts` to open **22** (SSH) and **443** (HTTPS), and `keypairs` to install your SSH key. `networkAccess.inboundPorts` opens the firewall rule *and* the port forwarding to the network's public IP together, so those ports are genuinely reachable — not just allowed in one place. 3. **Wait for it to be ready.** The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` and it has a public IP. Why only 22 and 443? Supabase's self-hosted architecture puts a single proxy in front of the whole stack, and everything else — its database, the auth and storage services, the internal APIs — is designed to talk to each other inside the Docker network, not over the public internet. So you expose **443** for the proxy (HTTPS) and **22** for your own SSH access, and you keep the rest internal. That's Supabase's own design; you're just honoring it at the firewall. If you later decide a port genuinely needs to be reachable, opening it takes **two** rules, not one: a firewall rule alone won't make traffic arrive. Ask your assistant to add it and it will create both `create_firewall_rule` *and* `create_port_forwarding_rule` (or use `enable_static_nat` to map a dedicated public IP to the VM). Keep that surface as small as Supabase's architecture allows. ## Set up Supabase over SSH With the VM running, the assistant moves to the terminal. This is the part Claude Code does in the same session. ```text SSH into the VM and set up Supabase using their official self-hosting Docker instructions: 1. Install Docker Engine and the Docker Compose plugin. 2. Pull Supabase's official self-hosting compose files onto the server. 3. Generate all the required secrets ON THE SERVER — the Postgres password, the JWT secret, and the anon and service keys derived from it. Do not print the secret values into our chat; write them straight into the env file and tell me only that they were generated. 4. Bring the stack up with docker compose and confirm all containers are healthy. ``` ### What your assistant will do 1. **Install Docker.** Over SSH it installs Docker Engine and the Compose plugin on the Ubuntu VM. 2. **Fetch Supabase's self-hosting setup.** It pulls Supabase's **official** self-hosting compose files (the ones Supabase publishes for running the stack with `docker compose`) onto the server. This includes Supabase's own bundled Postgres — that database is a component *of* the Supabase stack, lives inside the compose project, and is what your app connects to. 3. **Generate the secrets server-side.** Supabase needs a database password, a JWT secret, and the `anon` and `service` API keys derived from that secret. The assistant generates these **on the server** and writes them directly into Supabase's environment file — not into the chat transcript. Secrets that scroll through a chat window are a leak risk; keeping them on the box is the safe default. 4. **Bring the stack up.** It runs `docker compose up -d` from Supabase's compose directory, then checks that the containers report healthy. Ask the assistant to **generate every secret on the server and never echo the values into the chat** — *"write them into the env file and just tell me they were set."* You can read them back over SSH yourself when you need them (for example to configure your app). This keeps long-lived credentials out of any conversation history. ## Proxy, DNS, and HTTPS The last piece is making Supabase reachable on your domain over HTTPS. Supabase's stack already includes a proxy for routing to its internal services; you put a TLS-terminating reverse proxy in front so the only thing exposed on port 443 is encrypted traffic on your domain. ```text Now make Supabase reachable at {your-domain.com} over HTTPS: 1. Configure nginx on the VM as a reverse proxy in front of the Supabase stack, listening on 443. 2. Add a DNS A record pointing {your-domain.com} at the VM's public IP. 3. Once DNS resolves, provision a Let's Encrypt certificate with certbot and enable automatic renewal. Then confirm the Studio dashboard and the API both respond over HTTPS. ``` ### What your assistant will do 1. **Put a reverse proxy in front.** It configures nginx (or Supabase's own proxy, per their docs) to terminate TLS on 443 and route to the Supabase services on the Docker network. 2. **Point the domain at it.** It calls `list_dns_zones` to see if your domain is already hosted. If not, `create_dns_zone` adds it (you'll then update your registrar's nameservers to American Cloud's, which the assistant can show you). Then `create_dns_record` adds an `A` record for the domain pointing at the VM's public IP. 3. **Turn on HTTPS.** Once DNS resolves to the VM, it runs certbot to obtain a Let's Encrypt certificate, switches the proxy to HTTPS, and enables automatic renewal. 4. **Verify.** It checks that the Supabase Studio dashboard loads and the API responds over `https://{your-domain.com}`. When it's done, you have a full Supabase backend — database, auth, storage, and Studio — running on a server you own, behind your domain and HTTPS, with only the ports Supabase needs exposed. DNS changes take time to propagate — anywhere from a few minutes to a couple of hours. certbot needs the domain to resolve to the VM before it can issue a certificate, so the HTTPS step may have to wait. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* ## Moving an existing Supabase cloud project If you already have a project on Supabase cloud, migrating to your self-hosted instance is two pieces: the database and the storage objects. This is the high-level shape — your assistant can drive it, but treat a large or live project carefully. - **Database.** Take a logical dump of your cloud project's Postgres with `pg_dump` and restore it into your self-hosted stack's database with `pg_restore` (or `psql`). Your assistant can run both ends over SSH and tell you exactly which connection strings it's using. - **Storage objects.** If your project uses Supabase Storage, the objects move with `rclone` when the source is S3-compatible, or with Supabase's own storage tooling. Either way it's a copy from the old bucket into the new one. - **App config.** Point your app at the new backend by updating its `SUPABASE_URL` and the `anon` / `service` keys to the values from your self-hosted instance (the ones generated server-side during setup). For anything beyond a small project, **test the migration on a copy first.** Dump and restore into a throwaway self-hosted instance, point a staging copy of your app at it, and confirm auth, row-level security policies, and storage all behave before you cut production over. Schema extensions, custom roles, and large object stores are where surprises hide. ## Day-2: running it Once Supabase is live, treat the VM like any server you own. - **Snapshot before you upgrade.** Before bumping Supabase versions or changing the stack, ask your assistant to take a snapshot with `create_snapshot` so you can roll back. See [backups with your AI assistant](/docs/deploy-with-ai/backups) for the full backup-and-restore workflow. - **Resize as it grows.** When your data or traffic outgrows the box, your assistant can `scale_vm` to a larger size (it may require a brief restart) — no rebuild, no migration. - **Keep large files off the VM disk.** If your app stores user uploads or big assets in Supabase Storage, consider backing them with [object storage](/docs/deploy-with-ai/object-storage), which is S3-compatible and metered by usage rather than filling a fixed disk. - **When SSH isn't available.** If you ever lock yourself out, the assistant can reset access with `reset_vm_password` or open a browser-based session with `create_vm_console`. ## Troubleshooting **A container won't start or the stack is unhealthy.** Ask your assistant to *"SSH in and show me the docker compose logs for the unhealthy Supabase containers."* Most first-run issues are a missing or mistyped value in the env file — the assistant can read the logs and pinpoint it without printing the secrets back to you. **The domain doesn't load over HTTPS.** Have the assistant confirm DNS resolves to the VM and that certbot issued a certificate. If DNS is still propagating, certbot can't validate yet — wait and retry. If DNS resolves but the page is unreachable, ask it to *"list the firewall rules on the VM's public IP and confirm 443 is open"* (`list_firewall_rules`), and to check the proxy container is running. **Studio loads but the API doesn't respond.** This is usually proxy routing — the reverse proxy reaching the dashboard but not the API service. Ask the assistant to review the proxy config against Supabase's published routing and the running container ports. ## Next steps - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — put the app that talks to Supabase in front of it, on its own server and domain. - [Deploy with Docker Compose](/docs/deploy-with-ai/docker-compose) — the general pattern for running any compose-based stack on a VM. - [Backups with your AI assistant](/docs/deploy-with-ai/backups) — snapshots, off-site dumps, and restore drills so an upgrade can never cost you data. - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your stack and conventions so future steps are one prompt. ## Scale behind a load balancer You followed [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) (or the [Docker Compose recipe](/docs/deploy-with-ai/docker-compose)) and your app is live on one VM. Now it's getting more traffic than one box can handle, or you simply want redundancy so a single reboot doesn't take the site down. The fix is to run two identical VMs behind a load balancer: a [load balancer rule](/docs/load-balancing/load-balancer) on your network's public IP spreads incoming requests across both backends, and either one can go down without the site going with it. This recipe hands that whole job to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, it can inspect the VM you already have, clone it, replicate the app over SSH, wire up the load balancer, and verify both backends are healthy. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But scaling out also means replicating your app setup *on* the new server over SSH. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so one session can provision the second VM and configure it without you switching tools. That's the setup this recipe assumes. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when the assistant tells you to. Everything here is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. ## Before you start - One working VM running your app, created from the deploy recipe (you can SSH in, and the app serves on a local port behind nginx). - The SSH key from that first deploy — your assistant needs it to log into both the existing VM and the new one. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## The one prompt that does it Open your project in Claude Code and paste this. Read the cost estimate it shows you before approving anything. ```text My app is live on one VM on American Cloud and I want to scale it out behind a load balancer for capacity and redundancy. Plan it out first, then walk through it step by step: 1. Find my existing VM, its region, package, size, image, and the network it's attached to. Identify the public IP on that network. 2. Show me a monthly cost estimate for a second identical VM before creating anything. Wait for me to confirm. 3. Create a second VM with the same package, size, and image, attached to the SAME network as the first, with my SSH key installed. Wait until it's fully running. 4. Over SSH, replicate the app setup from the first VM onto the second: same runtime, same build, same service. Confirm the app answers on its local port on the new VM. 5. List the port forwarding rules on the public IP. The first deploy created forwards for the app's public ports to VM 1 — remove those (and only those; leave the SSH forward alone), because a load balancer rule and a port forward can't share the same public port. Tell me before you remove anything. 6. Create a load balancer rule on the network's public IP that balances the app's public port across backends, then assign BOTH VMs to it. Do this immediately after step 5 so the port is only briefly unserved. 7. Verify both VMs are listed as backends on the rule, then confirm the site still serves correctly through the public IP. My DNS already points at that public IP, so no DNS change should be needed — tell me if that assumption is wrong. ``` ### What your assistant will do Grounded in real MCP tools, here's the sequence: 1. **Inspect what you have.** It calls `list_vms` to find your VM, then `get_vm` for the full detail — region, package, the size (vCPU and memory), the image label, and the `network` it's attached to. It calls `list_public_ips_by_isolated_network` (or `list_public_ips`) to find the public IP serving that network, the one your domain already resolves to. 2. **Price the second VM first.** It calls `get_cost_estimate_vm` with the exact same region, package, size, and image as the original, and shows you the hourly and monthly numbers *before* creating anything. Two identical VMs cost roughly twice one — no surprises. 3. **Clone the box.** On your go-ahead, `create_vm` provisions the second VM with the same `vmPackage`, `vmSpecs`, and `image`, and — critically — the same `network` UUID as the first, so both VMs share one private network and one public IP. It installs your SSH key via `keypairs`. It does **not** add inbound app-port rules here: the load balancer rule (next) is what exposes the app on the public IP. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED`. 4. **Replicate the app over SSH.** Now in the terminal, it mirrors the first VM's setup onto the second — same runtime, same build, same `systemd` service listening on the same local port. If you wrote a deploy script in the first recipe, this is just running it against the new host. 5. **Clear the old path to VM 1.** Your first deploy exposed the app with port forwarding: the public IP's app ports (80/443) currently forward straight to VM 1. A load balancer rule can't share a public port with a port forward, so the assistant calls `list_port_forwarding_rules` on the IP, shows you the forwards for the app ports, and — with your okay — removes them with `delete_port_forwarding_rule`. It leaves the SSH forward in place. (The firewall rules for 80/443 stay too — they're still what admits the traffic.) 6. **Create the load balancer rule — right away.** It calls `create_load_balancer_rule` on the public IP (`ipId`) with a `publicPort` and `privatePort` matching your app (for example `"443"` → `"443"`, or `"80"` → the local port nginx listens on), an `algorithm`, and `protocol` `tcp`. The algorithm choices are `roundrobin` (even distribution, the usual default), `leastconn` (send each request to the backend with the fewest active connections — good for long-lived connections), or `source` (pin each client IP to the same backend — a simple way to keep a user on one box). Steps 5 and 6 happen back-to-back, so the app port is unserved for seconds, not minutes. 7. **Assign both backends.** It calls `assign_vms_to_load_balancer` with the rule ID and both VM UUIDs, so the rule fans traffic out to both. 8. **Verify.** It calls `list_load_balancer_instances` to confirm both VMs are attached to the rule, and checks each is `STARTED` with `get_vm`. Then it confirms the site still serves through the public IP. When it's done, requests hitting your public IP are spread across two VMs, and either one can be rebooted or fail without taking the site offline. A public port is served by **either** a port-forwarding rule **or** a load balancer rule — never both. Your single-VM deploy used forwards for the app ports, which is why step 5 removes them before the load balancer rule takes over. The same applies later: never add a forward back on a load-balanced port. ## Shared state: the part that breaks if you skip it Two VMs behind a load balancer means a request can land on *either* box. Anything one VM remembers that the other doesn't will produce confusing, intermittent bugs — a file that uploaded fine but 404s on the next request, a user who's logged in on one page and logged out on the next. Before you send real traffic to two backends, move shared state off the individual boxes. Your assistant can do each of these in one prompt. ### Uploads go to object storage With one VM, user uploads could live on its local disk. With two, an upload that lands on VM A isn't on VM B — so half your requests can't find it. Move file uploads to [object storage](/docs/deploy-with-ai/object-storage), which both VMs read and write over the network: ```text My app stores user uploads on the VM's local disk, but now there are two VMs behind the load balancer. Set up an American Cloud object storage bucket for uploads, give me the credentials, and update the app on BOTH VMs to read and write uploads to the bucket instead of local disk. Migrate any existing files on the first VM into the bucket. ``` ### The database moves to its own VM on the private network A database that lives on one of the app VMs is only reachable by that VM, and it competes with the app for resources. Give it its own VM on the same private network, reachable by both app VMs over the internal network and exposed to nothing public: ```text Right now PostgreSQL runs on my first app VM. Create a separate small VM on the SAME private network for the database, install PostgreSQL on it, and migrate my data over. Configure it to listen only on the private network so both app VMs can reach it, but it isn't exposed to the internet. Update both app VMs' config to point at the database VM's private address, and restart the app on each. ``` This keeps the database private — it's reachable across the internal network by the app VMs, and there's no public rule pointing at it. ### Sessions become stateless or shared If your app keeps login sessions in the memory of a single process, a user bounced to the other VM appears logged out. Make sessions survive the hop: ```text My app stores login sessions in memory on a single VM. Behind the load balancer that logs users out when they hit the other box. Switch sessions to either signed cookies (stateless) or a shared session store on the database VM, so a user stays logged in no matter which backend serves the request. Apply the change to both VMs. ``` The `source` algorithm (sticky sessions by client IP) can paper over in-memory session state, but it isn't a substitute for the fixes above — a client's IP can change, and pinning traffic undermines even balancing. Use it as a convenience, not as your state strategy. ## Rolling deploys with two backends Two VMs also unlock rolling deploys: take one backend out of rotation, update it, put it back, then repeat on the other. The load balancer keeps serving from whichever VM is still in. (Requests already in flight to a VM at the moment it's removed can be cut — for typical short web requests that passes unnoticed, but it's worth knowing.) ```text Do a rolling deploy of the latest committed code: 1. Remove the first VM from the load balancer rule so it stops getting traffic. Confirm the second VM is still serving. 2. Deploy the latest code to the first VM and restart its service. Check it responds correctly on its local port. 3. Re-assign the first VM to the rule. 4. Repeat the same steps for the second VM. At no point should both VMs be out of rotation at the same time. ``` Under the hood the assistant uses `remove_vms_from_load_balancer` to take a VM out of rotation, deploys to it, then `assign_vms_to_load_balancer` to return it — one VM at a time, so there's always a live backend. ## Triage: is traffic balanced and are both backends healthy? When something looks off, hand the assistant this: ```text Is traffic actually balanced and are both backends healthy? Check that: - The load balancer rule on my public IP is ACTIVE. - Both VMs are assigned to the rule and both are STARTED. - Each VM's app service is up and answering on its local port over SSH. - The rule's algorithm, public port, and private port match what the app listens on. Tell me which backend, if any, is the problem. ``` It works through `list_load_balancer_rules` and `list_load_balancer_instances` for the rule and its backends, `get_vm` for each VM's power state, and an SSH check of each app service. A rule that won't go `ACTIVE` usually means no healthy VM is attached, or the ports don't match what the app is listening on. ## Reaching individual VMs directly The load-balanced port flows through the rule on the public IP, so you don't open it per-VM. But you'll still want to SSH into each box. The first VM already has port 22 reachable from the deploy recipe. For the second, your assistant can open SSH on it by adding a port-forwarding rule on the shared public IP with a **distinct public port** for that VM (for example, forward public port `2202` → private port `22` on the second VM), since both VMs sit behind one IP. Ask it to *"give me SSH access to the second VM on the shared public IP using a separate public port, locked to my IP address."* It uses `create_port_forwarding_rule` for the forward and a matching firewall rule, restricted to your source CIDR rather than open to the world. ## When to step up to Kubernetes instead Two VMs behind a load balancer is the right shape for a steady workload you scale by hand: predictable traffic, a deploy you trigger yourself, a handful of backends you can reason about individually. It's simple, and you own every box. If your workload is spikier — bursty traffic you want to absorb automatically, many small services, rolling deploys and self-healing as a default rather than a script you run — that's the shape [Kubernetes](/docs/deploy-with-ai/kubernetes) is built for. American Cloud runs managed Kubernetes, and your assistant can provision and operate a cluster with the same MCP tools. Move to it when you find yourself wanting the cluster to add and replace backends on its own. ## Next steps - [Run on Kubernetes with your AI assistant](/docs/deploy-with-ai/kubernetes) — when you want autoscaling and self-healing instead of hand-managed VMs - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — shared uploads, assets, and backups both VMs can reach - [Load balancer rules](/docs/load-balancing/load-balancer) — the product reference for rules, algorithms, and backends in the console - [Backups and restore drills](/docs/deploy-with-ai/backups) — snapshot both VMs and prove the restores work - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your scaling and deploy conventions ## Backups & restore An untested backup is a guess. You only learn whether it works at the worst possible moment — the night you actually need it. The hard part of backups was never taking them; it's *proving they restore*, which means standing up a throwaway server, putting last night's data on it, and checking the result. That's enough work that most people skip it. The [American Cloud MCP server](/docs/mcp/overview) makes both halves cheap. Your assistant can snapshot your disks, set up off-site dumps, and — the part this page cares most about — run a full restore drill on a temporary VM and tear it down again, all from prompts you paste in. This recipe walks all three layers, then the drill. Most steps here create or destroy infrastructure, which is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server — see the [overview](/docs/mcp/overview) for setup and safety. The "what should I be backing up?" inventory prompt near the end is read-only, so it's a good place to start before you enable writes. ## Three layers of backup These aren't alternatives — a real strategy uses all three: 1. **Snapshots** — a point-in-time image of a whole disk, for fast rollback of an entire VM. 2. **Off-site dumps** — application-level exports (a `pg_dump`, a `tar` of your uploads) pushed to [object storage](/docs/deploy-with-ai/object-storage), so your data survives even if the VM and its disks are gone. 3. **The restore drill** — periodically restoring a dump onto a fresh VM and verifying it, so you *know* the backups are good rather than hoping. ## Layer 1: snapshots before a risky change A snapshot captures the exact state of a volume at a moment in time. It's the right tool for *whole-disk rollback*: take one right before a deploy, an OS upgrade, or a schema migration, and if it goes wrong you can put the disk back the way it was. Snapshots are scoped to the volume — a VM's root disk and any attached data volumes are separate snapshots, so to capture an entire server you snapshot each of its volumes. The natural moment is just before you change something. Paste this before tonight's deploy: > Snapshot every volume attached to my database VM, named with today's date and "pre-deploy", before tonight's deploy. Show me the cost estimate first. **What your assistant will do:** 1. Find the VM with `list_vms`, then list the volumes attached to it with `list_block_storage_volumes` (it can filter by the VM) so it knows the full set — root disk plus any data disks. 2. Call `get_cost_estimate_snapshot` for each of those volumes and show you the price *before* taking anything. Snapshots are billed for the storage they occupy, so this matters when a VM has large disks. Nothing is billed until you confirm. 3. On your go-ahead, call `create_snapshot` once per volume — `RootDisk` for the OS disk and `DataDisk` for attached volumes — naming each one like `db-vm-root-2026-06-05-pre-deploy` so you can tell them apart later. 4. Report the snapshot IDs so you have them if you need to roll back. To see what you've already got, ask any time — this is read-only: > List all my snapshots with their source volumes and dates, and flag any older than 30 days. That runs `list_snapshots` (and `get_snapshot` for detail), so it works even before you enable writes. Old snapshots cost storage; once you're confident a change stuck, have the assistant clean them up with `delete_snapshot` (see [rollback](#rolling-back-when-something-goes-wrong) for the confirmation framing). There's no recurring-snapshot scheduler — snapshots are something you take at a moment that matters (a deploy, a migration). For *unattended, nightly* protection, use off-site dumps (layer 2), which run on a cron on the VM. The two complement each other: snapshots for fast whole-disk rollback, dumps for durable off-server copies you can restore anywhere. ## Layer 2: nightly off-site dumps to object storage Snapshots live alongside your infrastructure. For data that has to survive the loss of the whole VM, you want an application-level export — a `pg_dump` or `mysqldump` for your database, a `tar` for your files — pushed off the server into a bucket. The implementation lives in the object-storage recipe: see [off-site backups from a VM](/docs/deploy-with-ai/object-storage#off-site-backups-from-a-vm) for the full prompt and what the assistant sets up (a cron job, retention, the AWS CLI against your endpoint). Database dumps are the same shape — run the dump command, then upload the file: > On my database VM, set up a nightly cron job that runs pg_dump of my app's > database, gzips it, and uploads it to my object storage bucket under > db-backups/ named with the date. Keep the last 14 days and prune older ones. In a coding agent that can reach the VM over SSH (like [Claude Code](/docs/mcp/claude-code)), the assistant fetches the bucket's S3 keys, writes the dump-and-upload script, schedules it with `cron`, and confirms the schedule. Run it once by hand to make sure the first dump lands in the bucket. Restoring one of these dumps costs nothing to download: American Cloud charges **no egress fees**, so pulling your backup back out is free, however large it is ([why that matters](/blog/egress-fees-explained)). That's the property that makes the next section practical — you can drill restores as often as you like without paying to fetch the data each time. ## Layer 3: the restore drill (the part everyone skips) This is the centerpiece. A backup you've never restored is a hypothesis. The drill turns it into a fact: provision a small temporary VM, restore last night's dump onto it, verify the data, then throw the VM away. Run it monthly. It costs about an hour of the smallest VM tier. Paste this: > I want to run a restore drill to prove my database backups actually work. > > 1. Show me a cost estimate for the smallest Ubuntu VM, then create a > temporary one for the drill (call it restore-drill so it's easy to spot). > Wait for it to be running. > 2. Over SSH, install PostgreSQL, pull the most recent dump from my object > storage db-backups/ bucket, and restore it into a fresh local database. > 3. Verify the restore: list the tables, show row counts for the main ones, > and spot-check a few recent records so I can confirm they look right. > Then start my app against this restored database and confirm it boots. > 4. Give me a short report: which dump you used, its date, the row counts, > and whether the app came up. > 5. When I confirm I've seen the report, delete the temporary VM so it stops > costing anything. **What your assistant will do:** 1. **Price and provision a throwaway VM.** It calls `get_cost_estimate_vm` for the smallest Ubuntu tier and shows you the number, then `create_vm` for a small VM (an isolated network and port 22 open is enough — nothing public needs to reach a drill box). It polls `get_vm` until the status reaches `STARTED`. 2. **Restore the dump onto it.** Over SSH it installs PostgreSQL, fetches the latest object from your `db-backups/` prefix (free to download — no egress fees), and restores it into a clean local database. It's reading from the bucket, so your real backups are never touched. 3. **Verify, don't assume.** It lists tables, reports row counts for your main tables, spot-checks a few of the newest records, and boots your app pointed at the restored database to confirm the application actually comes up against the data — not just that the file imported without error. 4. **Report.** You get the dump's date, the counts, and a pass/fail on the app boot. This is the artifact that tells you the backup is real. 5. **Tear it down.** `delete_vm` destroys the temporary VM and its disk so it stops billing. This is **destructive** — the assistant will describe that the drill VM and everything on it (just the throwaway restore) is permanently gone, and clients that support confirmations will prompt before it runs. That's expected here: the drill VM is disposable by design, and deleting it is how the drill stays cheap. The whole thing is one prompt and roughly an hour of a tiny VM. Put it on the calendar monthly. The first time it surfaces a dump that *doesn't* restore — a missing extension, a truncated upload, a schema the app no longer matches — you'll be very glad you found out during a drill instead of during an outage. ## Rolling back when something goes wrong When you actually need a backup, you have two tools, and they're not interchangeable. Tell your assistant what broke and let it explain which fits before it acts: - **`revert_snapshot` — whole disk, back to a point in time.** This restores the entire volume to the snapshot's state. **Everything written to that disk since the snapshot was taken is overwritten and lost** — it's destructive and can't be undone. It's the right move when a change corrupted the system broadly (a bad OS upgrade, a botched migration) and you want the machine exactly as it was at the snapshot. Because it's irreversible, the assistant will spell out the snapshot's timestamp and what you'd lose, and confirmation-capable clients will prompt before reverting. - **Restoring a dump — surgical.** Pulling a `pg_dump` back into the database fixes just the data, without touching the rest of the disk or the OS. It's the right move when the problem is data-level (a bad delete, a corrupted table) and the server itself is fine. A good prompt names the symptom and asks for the recommendation first: > A migration I ran an hour ago corrupted the orders table. I have a > pre-deploy snapshot of the database VM from before the migration and a > nightly dump in object storage. Walk me through the options — which one > loses the least, and what exactly would I lose with each — then do the one > I pick. The assistant lays out the trade-off (revert loses the last hour of *everything* on the disk; restoring just the dump loses changes since the dump but keeps everything else), waits for your choice, and only then runs the destructive step — with a confirmation. ## What should I be backing up? If you're not sure where the gaps are, have the assistant take inventory. This is **read-only**, so it works with a read-only key — a good first prompt before you enable writes: > Inventory my VMs and their attached volumes. For each one, tell me when it > was last snapshotted, and flag any VM that has no recent snapshot and no > obvious off-site dump job. Where am I exposed if a disk failed tonight? **What your assistant will do:** it calls `list_vms`, then `list_block_storage_volumes` and `list_snapshots` (or `list_block_storage_snapshots` per volume) to line up each volume against its most recent snapshot. It can't see inside a VM's crontab without SSH access, but it can flag every volume with no recent snapshot and ask you which ones have a dump job — turning "I think we have backups" into a concrete list of what's covered and what isn't. Close the gaps with the prompts above. ## Next steps - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — the bucket, the keys, and the nightly-dump cron that layer 2 builds on. - [Block storage and snapshots](/docs/block-storage/block-storage) — how volumes and snapshots work from the dashboard. - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — record your backup conventions so your assistant follows them every time. - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, storage, and networking. - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — the recipe most of these backups are protecting. ## Migrate from Vercel Vercel is a great place to start a Next.js app. But somewhere past the free tier — a spike in serverless invocations, image-optimization charges, bandwidth overages, a function timeout you can't tune — the bill stops matching the value, and the platform starts deciding things for you. This recipe moves your app to a server you own on American Cloud, where the cost is predictable and the runtime is yours. You don't do the Linux part. With the [American Cloud MCP server](/docs/mcp/overview) connected to your AI assistant, the assistant reads your repo, maps every Vercel feature to its American Cloud equivalent, prices the move so you can compare it against your real Vercel bill, provisions the server, deploys, and walks you through a careful DNS cutover that keeps Vercel serving traffic until you're confident. This is the same deployment engine as [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — read that first if you want the underlying mechanics. This page is about doing it *to an app that's already in production somewhere else*, which mostly means: inventory carefully, and cut over without downtime. Provisioning and DNS changes are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety. The inventory phase below is fully read-only — you can do all of it with a read-only key before committing to anything. ## What this looks like The migration runs as a guided conversation in five phases. Phases 1 and 2 are read-only — your assistant inspects and plans, nothing is created or billed. Phases 3 through 5 do the actual move. 1. **Inventory** — the assistant reads your repo and your Vercel config and produces a migration map. 2. **Plan and price** — it proposes the American Cloud equivalent and a cost estimate to set against your Vercel bill. 3. **Provision and deploy** — it builds the server and ships your app (leaning on the [deploy recipe](/docs/deploy-with-ai/deploy-nextjs)). 4. **Map the features** — custom domains, env vars, cron jobs, blob storage, and serverless routes each get a home. 5. **Cut over** — lower DNS TTL ahead of time, deploy, verify against the new server, switch DNS, then decommission Vercel once you're sure. Do it in a [Claude Code](/docs/mcp/claude-code) session: that client combines the American Cloud tools with your terminal, so the same conversation can read the repo, provision the VM, and run the deploy steps over SSH. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when prompted. ## Phase 1: inventory your app (read-only) Before moving anything, get an honest picture of what Vercel is actually doing for you. Some of it is your app (a `next.config`, your routes); some of it is Vercel platform features (a `vercel.json`, environment variables, cron entries, custom domains) that need an explicit home on the new server. Open your project and paste this. ```text I'm planning to migrate this Next.js app off Vercel to a VM I own on American Cloud. Don't change or create anything yet — this is a read-only inventory pass. Read the repo and build me a migration map: 1. Read next.config (js/ts/mjs) and tell me: the output mode (default, "standalone", or "export"), any image domains / remotePatterns, redirects, rewrites, headers, and anything that assumes the Vercel runtime. 2. Read vercel.json if it exists. List every cron entry, rewrite, redirect, header, and any function/region settings. 3. List the routes that are serverless or edge functions (app/api/* route handlers, middleware.ts, any "edge" runtime exports). Note anything that uses the Vercel-specific request/response or KV/Blob/Postgres SDKs. 4. Read package.json: Node version, build and start scripts, and whether the build is memory-hungry. 5. Make a checklist of the environment variables this app reads (scan for process.env.* usage). I'll supply the values — do NOT ask me to paste secrets into the chat; just list the names. 6. Note any custom domains the app serves on (from my notes or config) and whether the app uses Vercel Blob, Vercel KV, or a hosted Postgres. Output a single migration map: what moves as-is, what needs a server-side equivalent, and what I need to provide (env values, domain list, DB dump). ``` ### What your assistant will do This phase touches your filesystem only — no MCP write tools, no API calls that cost anything. - **Reads your code.** It opens `next.config`, `vercel.json`, `package.json`, `middleware.ts`, and your `app/api` route handlers directly from the repo. - **Classifies each piece.** Static export vs. standalone server changes the whole plan (see the next phase). Edge/serverless routes become normal routes on a long-running server. Cron entries in `vercel.json` become scheduled jobs on the VM. - **Builds the env-var checklist** by scanning for `process.env` usage, so nothing silently goes missing on the new server. It lists *names*, never asks you to paste secret *values* into the chat — you'll put those on the server directly. - **Flags storage.** If the app uses Vercel Blob or KV, those map to American Cloud object storage. If it uses a hosted Postgres, that becomes PostgreSQL running on the VM (more on both below). The output is a plain-language map you can sanity-check before a single resource exists. ## Phase 2: plan and price (read-only) Now turn the map into a concrete American Cloud plan with a number attached — *before* creating anything. The MCP server's cost-estimate tools are read-only, so the assistant can price the whole setup and you can lay it next to your Vercel invoice. ```text Based on the migration map, propose an American Cloud setup and price it. Don't create anything yet. - If my app builds with "standalone" output (a normal Next.js server), plan a single VM: recommend a region near my users, a current Ubuntu LTS image, and the smallest VM package that can build and run this app. - If my app is a static "export", plan the smallest VM tier — no Node process to run, nginx serves the exported files directly. - List the regions, images, and VM packages so I can see the options. - Then call the cost-estimate tool for the VM and show me the hourly and monthly numbers. Add a public IP if one's needed, and object storage if the migration map calls for it. - Give me a single monthly total I can compare against my Vercel bill. ``` ### What your assistant will do - **Picks the shape from the inventory.** A standard Next.js app (default or `output: "standalone"`) becomes one long-running server: it calls `list_regions`, `list_images` filtered to Ubuntu, and `list_vm_packages` to find a region and a small compute tier within the package's CPU/memory limits. - **Simplifies for static exports.** If your app is `output: "export"` (or a plain static site), there's no Node process to run — nginx serves the exported files directly, so the smallest VM tier is plenty and there's one less moving part to operate. - **Prices it before building.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image (plus `get_cost_estimate_public_ip`, and `get_cost_estimate_object_storage` if the plan includes object storage for Blob or KV data) and shows the monthly figure. Nothing is billed until you say go. This is the comparison that matters. American Cloud bills a flat rate for the server you choose — not per serverless invocation, per image transform, or per GB of bandwidth. Put the assistant's monthly estimate next to your last few Vercel invoices and decide with real numbers. (For the why behind this, see [Escaping vendor lock-in](/blog/vendor-lock-in-escape-guide).) ## Phase 3: provision and deploy With the plan approved, the build-and-deploy itself is exactly the flow documented in [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — provision a VM, open ports 22/80/443, install Node and nginx over SSH, run the standalone build as a `systemd` service behind nginx, and turn on HTTPS with Let's Encrypt. The one difference for a migration: **don't point your live domain at the new server yet.** You want to deploy and fully test against the VM's IP first, while Vercel keeps serving your real traffic. So run the deploy recipe through the build and HTTPS steps, but hold the DNS switch for Phase 5. The "execute the migration" prompt below wires this together end to end. ## Phase 4: map the Vercel features Most of a Vercel migration is translating platform features into things that run on your own server. Here's how each one maps, and which MCP tools or server-side steps your assistant uses. | Vercel feature | On American Cloud | How | |---|---|---| | Custom domains | Hosted DNS zone + records | `create_dns_zone`, `create_dns_record` (`A` record at the VM's public IP); update your registrar's nameservers | | Environment variables | Server environment / `systemd` unit | Written into the app's env file or the `systemd` service over SSH — values go on the server, never into chat | | Cron jobs (`vercel.json`) | `cron` or `systemd` timers | The assistant writes a `systemd` timer (or crontab entry) per cron route over SSH | | Image optimization | Handled by the Next.js standalone server | `next/image` optimizes at runtime on your server; no per-transform billing | | Vercel Blob / KV | Object storage | `create_object_storage_unit`, `create_object_storage_bucket`, `get_object_storage_keys` — S3-compatible; see [object storage](/docs/deploy-with-ai/object-storage) | | Serverless / edge functions | Routes on the long-running server | `app/api` route handlers and middleware run in the same Next.js process — often simpler: no cold starts, no per-invocation pricing | | Hosted Postgres | PostgreSQL on the VM | Installed over SSH, bound to `localhost`; migrate data with `pg_dump` / `pg_restore` | A few of these are worth a closer look. ### Serverless and edge functions On Vercel, each `app/api` route or piece of middleware is deployed as an isolated function that spins up per request. On your own server, they're just routes in the one long-running Next.js process. Nothing in your code has to change — the standalone server handles them. In practice this is usually *simpler*: no cold starts, no invocation limits, no per-call billing. If a route relied on a Vercel-specific runtime API, your assistant flags it in Phase 1 so you can swap it for the standard Node equivalent. ### Cron jobs Vercel cron entries are just a schedule pointing at a route. Your assistant reads them from `vercel.json` and recreates each one as a `systemd` timer (or a crontab line) on the VM that hits the same route on the same schedule — over SSH, so they survive reboots. ### Blob and KV storage If your app stores files in Vercel Blob, your assistant creates an S3-compatible object storage unit and bucket (`create_object_storage_unit`, `create_object_storage_bucket`), fetches the access keys (`get_object_storage_keys`), and updates your app to talk to it with any S3 client. The full walkthrough is in [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage). Key-value usage typically becomes a small store on the server (for example Redis installed over SSH alongside the app). ### A hosted database If you're on Vercel Postgres or another hosted database, your assistant installs PostgreSQL directly on the VM over SSH, bound to `localhost` so it's never exposed to the internet, and migrates your data with `pg_dump` from the old database and `pg_restore` into the new one. Ask for it explicitly: ```text This app uses a hosted Postgres. On the VM, install PostgreSQL listening only on localhost, create a database and user for this app, and put the connection string in the app's environment file. Then walk me through dumping my current database with pg_dump and restoring it here with pg_restore, and verify the row counts match before I cut over. ``` ## Phase 5: cut over without downtime This is the part that's unique to migrating a live app. The goal: bring the new server fully online, prove it works, and only *then* move traffic — with Vercel still up as your safety net. **Lower your DNS TTL first — a day or two ahead if you can.** TTL is how long resolvers cache your DNS records; a high TTL means a cutover takes hours to take effect everywhere. Drop it to something short (60 seconds) *before* the migration so that when you flip the record, traffic moves fast and a rollback is just as quick. Your assistant can do this on an American Cloud zone, or tell you what to change at your current DNS provider. **Test against the new server before you touch DNS.** Your assistant can hit the VM's public IP directly with the right `Host` header — e.g. `curl -H "Host: your-domain.com" https://VM_IP/ --resolve your-domain.com:443:VM_IP` — so it sees exactly what visitors will see, while real DNS still points at Vercel. Or it can add a temporary line to your local `hosts` file mapping your domain to the VM's IP, so you can click through the whole site in a browser before any public change. Ask: *"verify the migrated site against the VM's IP with my domain's Host header, and check every route the inventory found."* Here's the prompt that runs the migration end to end and ends on a careful cutover: ```text Execute the migration to American Cloud using the plan and prices we agreed on. Narrate each step and pause before anything destructive or anything that moves real traffic. 1. Provision the VM per the deploy-nextjs recipe: small Ubuntu VM, my SSH key, ports 22/80/443 open. Wait until it's STARTED with a public IP. 2. Deploy this repo: Node LTS + nginx, standalone production build, run as a systemd service behind an nginx reverse proxy. 3. Recreate my environment variables on the server (I'll give you the values to put in the env file directly — not in chat). Recreate each vercel.json cron entry as a systemd timer. 4. If the inventory found Blob/KV or a hosted database, set up object storage and/or PostgreSQL-on-the-VM and migrate the data as we discussed. 5. Provision a Let's Encrypt certificate so the VM serves HTTPS for my domain, even though DNS doesn't point here yet (use the DNS-01 path or a temporary verification as needed). 6. Before any DNS change: verify the site against the VM's IP using my domain's Host header. Walk every route from the inventory. Show me the results. 7. When I confirm it's good: lower the DNS TTL if it isn't already, then switch the A record for my domain to the VM's public IP. 8. Watch resolution until my domain points at the VM, then confirm the live site loads over HTTPS. Leave my Vercel deployment running untouched. ``` ### What your assistant will do 1. **Builds and deploys** exactly as in the [deploy recipe](/docs/deploy-with-ai/deploy-nextjs): `create_vm` with `networkAccess` to open 22/80/443 and `keypairs` for your SSH key, polling `get_vm` until `STARTED`, then Node, nginx, the standalone build, and a `systemd` service over SSH. 2. **Restores your config.** Env vars go straight into the server's env file or the `systemd` unit; cron entries become timers. Storage and database data move per Phase 4. 3. **Gets HTTPS ready early** so the new server can serve your domain over TLS before traffic arrives. 4. **Verifies against the IP.** Using a `Host`-header `curl` or a temporary `hosts` entry, it checks every route the inventory found — all while Vercel still serves your users. 5. **Cuts over deliberately.** Only on your confirmation does it switch the `A` record (`update_dns_record` on an American Cloud zone, or it tells you the change to make at your DNS provider) to the VM's public IP, then watches resolution until your domain points at the new server. 6. **Leaves Vercel running.** Because you lowered the TTL, rollback is fast: if anything looks wrong, point the record back at Vercel and you're restored in seconds. ### Decommission Vercel — when you're sure Give it a day or two. Watch the new server's traffic and error logs, confirm cron jobs are firing, check that uploads land in object storage. When you're confident the new server is carrying everything Vercel used to, then — and only then — tear down the Vercel deployment. There's no rush: keeping it up a little longer costs little and buys you a clean rollback the whole time. ```text The migrated site has been healthy for a couple of days. Confirm the VM is handling traffic, the systemd timers (former crons) have run on schedule, and nothing is still calling Vercel. Then give me a checklist for safely removing the Vercel project. ``` ## Next steps - [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — the full provision-and-deploy mechanics this playbook builds on - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — replacing Vercel Blob, plus uploads and backups - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — capture your deploy conventions so future sessions repeat them - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, storage, networking, and DNS - [MCP server overview](/docs/mcp/overview) — setup, safety, and the read-write key you'll need for the cutover ## Migrate from AWS Leaving AWS usually stalls on the same thing: nobody wants to hand-translate a sprawl of EC2 instances, S3 buckets, DNS records, and security groups into a new provider's console without dropping something. This playbook turns that into a conversation. Your AI assistant reads your AWS account through the `aws` CLI, plans the move, prices the American Cloud side, and — when you say go — builds it with the [American Cloud MCP server](/docs/mcp/overview). The economics are why teams start: American Cloud charges **zero egress fees** and pricing that runs lower than the hyperscalers (see [how to move your workloads off AWS](/blog/how-to-move-your-workloads-off-aws)). The hard part has always been the mechanics. That's what your assistant handles here. ## What this playbook covers This is the well-trodden path: the stack most small and mid-size teams actually run on AWS. - **EC2 instances** → American Cloud VMs - **S3 buckets** → object storage (S3-compatible) - **Route 53 zones** → hosted DNS zones and records - **ELB / ALB** → load balancers - **EKS clusters** → managed Kubernetes - **RDS databases** → PostgreSQL or MySQL on a VM If your architecture is deeply serverless — most of your logic lives in Lambda functions, Step Functions, and event glue rather than on long-running servers — that's a different journey. The first move there is re-platforming onto a long-running server or [Kubernetes](/docs/deploy-with-ai/kubernetes); once your code runs as a service you can host anywhere, this playbook applies again. Everything below assumes workloads that run on instances, in containers, or behind a load balancer. ## How it works: two credentials, one conversation You give your assistant two things and it does the rest: 1. **The `aws` CLI, read-only.** Configure it with credentials scoped to read your AWS account (the AWS-managed `ReadOnlyAccess` policy is the simplest whitelist). Your assistant runs `aws ec2 describe-instances`, `aws s3 ls`, `aws route53 list-hosted-zones`, and similar commands to inventory the source. Nothing on AWS changes. 2. **The American Cloud MCP server, for the destination.** This is where resources get created. Start read-only to explore and price, then switch on writes when you're ready to build. Provisioning is a write operation. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety. Keep the AWS side read-only the whole time — the migration only *reads* from AWS and *writes* to American Cloud, so there's no risk of touching your live AWS resources. A coding agent like [Claude Code](/docs/mcp/claude-code) is the ideal driver, because the migration needs a terminal as much as it needs API calls: rsync over SSH, `pg_dump`, `rclone`. The assistant provisions infrastructure *and* runs the data-movement commands in one session. ## The phases You don't have to cut over everything at once. The whole point is that the bill shrinks **service by service** — each workload you move is one line item that stops on AWS and starts (smaller) on American Cloud. The phases: 1. **Inventory** *(read-only)* — your assistant catalogs the AWS account. 2. **Plan and price** *(read-only)* — it maps each resource to an American Cloud equivalent and produces a cost estimate you compare against your AWS bill. 3. **Provision** — it builds the destination: networks, VMs, storage, load balancers, clusters. 4. **Transfer data** — buckets, disks, and databases are copied across and verified. 5. **Cut over DNS** — records are recreated, TTLs lowered ahead of time, then flipped. 6. **Verify** — traffic is on American Cloud and everything checks out. 7. **Decommission** — you tear down the AWS resource for that workload, and that line item is gone. Repeat per workload. A single non-critical service first; the rest once you trust the process. ## Phase 1: inventory your AWS account Point your assistant at the read-only `aws` CLI and ask it to take stock. Paste this: ```text I'm planning to migrate from AWS to American Cloud. I've configured the aws CLI with read-only credentials. Don't change anything on AWS — only read. Inventory my AWS account and build a migration table. For each of these, list what exists with the details I'll need to recreate it elsewhere: 1. EC2 instances: name/tag, instance type (vCPU + memory), region, OS, root + attached EBS volume sizes, and which are actually running. 2. S3 buckets: name, region, rough object count and total size, and whether each is public or private. 3. Route 53 hosted zones: domain, and every record (type, name, value, TTL). 4. Load balancers (ELB/ALB): listeners, target groups, and which instances sit behind each. 5. EKS clusters: Kubernetes version, node group sizes, and node counts. 6. RDS instances: engine (PostgreSQL/MySQL) and version, instance size, and storage size. Summarize it as a table I can review, and flag anything that looks unusual or that won't map cleanly to a standard VM/storage/DNS/load-balancer/Kubernetes setup. ``` ### What your assistant will do This phase is entirely read-only on both sides — it touches no MCP write tools and changes nothing on AWS. 1. **Walk the AWS account** with `aws ec2 describe-instances`, `aws s3 ls` / `aws s3api`, `aws route53 list-hosted-zones` and `list-resource-record-sets`, `aws elbv2 describe-load-balancers`, `aws eks describe-cluster`, and `aws rds describe-db-instances`. 2. **Normalize the findings** into instance sizes (vCPU + memory), volume sizes, bucket footprints, DNS records, and cluster shapes — the inputs the American Cloud side needs. 3. **Surface the edge cases** up front: anything serverless, anything with an unusual networking shape, public-vs-private buckets. Honest scoping here saves surprises later. You finish this phase with a migration table and zero changes made anywhere. ## Phase 2: plan and price the American Cloud side Now have your assistant map the inventory to American Cloud and put a number on it — still without creating anything. ```text Using that inventory, propose the American Cloud equivalents and price them. Don't create anything yet — read-only and cost estimates only. For each AWS resource, map it like this: - EC2 instance -> a VM with matching vCPU/memory and disk - S3 bucket -> an object storage unit + bucket - Route 53 zone -> a hosted DNS zone with the same records - ELB/ALB -> a load balancer rule with the same backends - EKS cluster -> a managed Kubernetes cluster of similar size - RDS instance -> PostgreSQL/MySQL installed on a VM sized for it Pick a region close to my current AWS region. For every compute resource, call the matching cost-estimate tool and give me a total monthly estimate for the American Cloud side. I'll compare it against my AWS bill. ``` ### What your assistant will do 1. **Choose sizes and a region.** It calls `list_regions`, `list_vm_packages`, `list_images`, and `list_kubernetes_packages` to find equivalents — a VM tier whose CPU/memory bracket the EC2 instance, a Kubernetes node package matching the EKS node group, an Ubuntu image for the RDS-replacement VM. 2. **Price every piece without building it.** The MCP server exposes cost-estimate tools that take the same arguments as the create tools: `get_cost_estimate_vm`, `get_cost_estimate_object_storage`, `get_cost_estimate_kubernetes`, and others. The assistant calls these to assemble a monthly total. Nothing is billed. 3. **Hand you the comparison.** You get an American Cloud monthly estimate to set against your current AWS bill — including the egress line, which on American Cloud doesn't exist: there are no egress fees. Do the **S3 transfer first** in the build-out, and **verify checksums** when it finishes. Data transfer out of S3 is almost always the long pole — it can take hours or days for a large bucket — and it's the one place AWS's egress fee bites on the way out (see [egress fees explained](/blog/egress-fees-explained)). Kick it off early so it runs in the background while you provision everything else, and confirm object counts and checksums match before you delete anything on the AWS side. ## Phase 3 onward: execute one phase at a time With the plan priced and writes enabled, drive the build phase by phase. Run each as its own prompt so you can review between steps — this keeps you in control and lets the assistant pause for confirmation on anything irreversible. ```text Let's execute the migration plan. Do it one phase at a time and stop for my confirmation between phases. We have a read-write key and writes are enabled. Phase 3 — provision the destination: - Create the network(s), then the VMs that replace my EC2 instances (matching sizes), each with my SSH key and the right inbound ports open. - Create the object storage unit and buckets that replace my S3 buckets. - If I have an EKS cluster, create the equivalent managed Kubernetes cluster. - For my RDS database, create a VM sized for it and install PostgreSQL (or MySQL) over SSH, listening only on localhost. Show me the cost estimate for anything new before you create it, and report the IPs and identifiers when each is up. When I confirm, move to Phase 4 (data transfer): start the S3 bucket copy first, then the EC2 disk data, then the database dump and restore. ``` ### What your assistant will do **Provision (Phase 3).** Grounded in real MCP tools: - **Networks and VMs.** It creates an isolated network if needed, then `create_vm` for each EC2 replacement — passing `keypairs` (after checking `list_ssh_keys` or making one with `create_ssh_key`) and `networkAccess` to open the inbound ports your instances actually use. It polls `get_vm` until each reaches `STARTED` with a public IP. - **Object storage.** `create_object_storage_unit` and `create_object_storage_bucket` stand up the S3 replacements; `get_object_storage_keys` returns the access key, secret, and endpoint for the transfer step. - **Kubernetes.** `create_kubernetes_cluster` (sized from `list_kubernetes_packages`, version from `list_kubernetes_versions`) builds the EKS equivalent; `get_kubernetes_cluster_config` later returns the kubeconfig so you can apply your manifests. See [run on Kubernetes](/docs/deploy-with-ai/kubernetes) for the full recipe. - **The RDS replacement.** It creates a VM and, over SSH, installs PostgreSQL or MySQL bound to `localhost` so the database isn't exposed to the internet — the same pattern as the [database-on-a-VM step in the Next.js recipe](/docs/deploy-with-ai/deploy-nextjs). **Transfer data (Phase 4).** This is the heart of the move, and order matters — S3 goes first. - **S3 → object storage.** Because both ends speak S3, the assistant uses `rclone` to sync bucket-to-bucket: an AWS remote on one side, an American Cloud remote (the keys from `get_object_storage_keys`) on the other. American Cloud charges nothing to receive the data, so only AWS's egress applies. When the sync completes, it compares object counts and checksums before anything is removed from AWS. For the S3 wiring details, see [object storage with your AI assistant](/docs/deploy-with-ai/object-storage). - **EC2 disk data → VM.** It `rsync`s application files, configs, and data directories from each EC2 instance to its replacement VM over SSH, then installs and starts the services so the new VM mirrors the old. - **RDS → PostgreSQL/MySQL on a VM.** It runs `pg_dump` (or `mysqldump`) against the RDS endpoint, transfers the dump, and restores it into the database on the new VM, then updates the application's connection string to point at `localhost` (or the private network). ## Phase 5: cut over DNS with a low TTL DNS is what actually moves your traffic, so it's deliberate and reversible. ```text Phase 5 — DNS cutover. First, the records serving traffic today live on Route 53, so tell me exactly which TTLs to lower there (down to 60-300 seconds) and I'll make that one change in the AWS console; then we wait for the old TTL to expire so changes propagate fast. Meanwhile, recreate my Route 53 zone and records on American Cloud DNS with short TTLs. When I confirm the new servers respond correctly, switch the A/CNAME records to the new IPs. Keep the old AWS resources running until I've verified the cutover. ``` ### What your assistant will do 1. **Lower TTLs where DNS is served today.** The records currently answering queries live on Route 53, so that's where TTLs must drop ahead of the flip — the one deliberate change to make on the AWS side (do it yourself in the console, or grant the assistant that single write). Wait out the old TTL before cutting over. 2. **Recreate the zone and records.** `create_dns_zone` for the domain, then `create_dns_record` for each record from the Route 53 inventory — same names, types, and values, created with short TTLs from the start (`update_dns_record` adjusts them later). You'll point your registrar's nameservers at American Cloud when you're ready; the assistant shows you which to set, and that delegation change itself can take a few hours to propagate. 3. **Switch the targets** only on your go-ahead, pointing the A and CNAME records at the new VM and load-balancer IPs. For load balancers specifically, it uses `reserve_public_ip`, `create_load_balancer_rule` (with the algorithm and ports matching your ELB/ALB listeners), and `assign_vms_to_load_balancer` to put the new VMs behind it — the DNS record then points at the load balancer's IP. See [DNS management](/docs/dns/dns-management) and [load balancers](/docs/load-balancing/load-balancer) for the underlying concepts. ## Phase 6: verify Before you tear anything down on AWS, confirm the new stack is serving real traffic. ```text Phase 6 — verify. Confirm DNS now resolves to the American Cloud IPs, that the sites/apps respond over HTTPS, that both backends are attached to the load balancer and their VMs are running, and that the app can reach its database. Spot-check that a few known S3 objects exist in the new buckets with matching sizes. Give me a go/no-go summary. ``` Your assistant checks resolution, hits the endpoints, confirms load-balancer backends are healthy, verifies the app reaches its migrated database, and re-checks a sample of object-storage keys against the source. You get a clear go/no-go before committing. ## Phase 7: decommission, one service at a time Once a workload is verified on American Cloud, retire its AWS counterpart — and that line item disappears from your AWS bill. Because you've moved service by service, there's no big-bang switchover and no moment where everything is in flight at once. ```text Phase 7 — decommission. I've verified [this workload] on American Cloud. Walk me through retiring its AWS resources safely: confirm nothing else still depends on them, then give me the exact aws CLI commands to terminate the EC2 instance / delete the bucket / remove the load balancer. I'll run the destructive AWS commands myself after I review them. ``` Deletions on AWS stay in your hands — the assistant proposes the commands and confirms there are no remaining dependencies, but you run anything destructive on the source. Repeat the whole cycle for the next workload. Each pass, the AWS bill gets smaller and the American Cloud side carries more, until the migration is simply done. ## Next steps - [MCP server overview](/docs/mcp/overview) — setup, read-only-by-default safety, and the read-write key you need for the build phases. - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — the S3-compatible details behind the bucket transfer. - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — the full recipe for the EKS-equivalent cluster. - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — including the database-on-a-VM pattern used for RDS replacement. - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your conventions so future moves and deploys are one prompt. - [How to move your workloads off AWS](/blog/how-to-move-your-workloads-off-aws) and [egress fees explained](/blog/egress-fees-explained) — the economics that make the case. ## Migrate from Heroku Heroku made deploying easy, and the dyno model made it expensive. Once you're past a hobby app, you're paying for a web dyno, one or more worker dynos, a Postgres add-on, a Redis add-on, and maybe Scheduler — each its own line on the bill, none of them a server you can size yourself. Here's the reframe that makes the move tractable: **a Heroku app is just processes, config, and a database.** Your `Procfile` already lists the processes. Your config vars are environment variables. Your data lives in Postgres (and maybe Redis). None of it is Heroku-specific magic — it's a normal Linux deployment wearing a platform. This recipe hands that translation to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant reads your `Procfile`, turns each line into a `systemd` service on a VM you own, installs the runtime your app needs, migrates your Postgres data with `pg_dump`/`pg_restore`, points your domain at the new server, and turns on HTTPS — all from prompts you paste in. On American Cloud, the same workload that forced several dynos usually fits on **one VM** you can resize as you grow. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But migrating an app also means running commands *on* the server — SSH in, install the runtime, restore a database dump, configure services. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so one session can provision the VM, read your local repo, and deploy to the server without switching tools. That's the setup this recipe assumes. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when the assistant tells you to. Provisioning and migrating are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only while you take inventory and plan, then switch the key when you're ready to build. ## How a Heroku app maps to a VM Every piece of a classic Heroku app has a direct, well-understood equivalent on a server. Your assistant works from this mapping: | On Heroku | On your American Cloud VM | |---|---| | Web dyno (`web:` in `Procfile`) | A `systemd` service, with nginx in front as a reverse proxy | | Worker dyno (`worker:` in `Procfile`) | A `systemd` service that restarts on crash and on boot | | Heroku Postgres | PostgreSQL installed on the VM, migrated with `pg_dump` / `pg_restore` | | Heroku Redis | Redis installed on the same VM (or a separate one) | | Heroku Scheduler | `cron` jobs on the VM | | Config vars | An environment file on the server that every service reads | | Buildpacks | The assistant installs the runtime directly — it reads your `Gemfile`, `package.json`, or `requirements.txt` to know what's needed | | Custom domain + Automated Certificate Management | DNS records via the [hosted DNS](/docs/dns/dns-management) tools plus a Let's Encrypt certificate from certbot | The shape that fits this best is a classic app — Rails, Node, or Python — with a `web` process, one or more `worker` processes, Postgres, and maybe Redis. That's exactly the workload Heroku's dyno pricing punishes, and exactly the workload one VM handles comfortably. ## Before you start - Your app in a local git repo, with its `Procfile` (and `app.json` if you have one). - Access to your Heroku app so you can run `heroku pg:backups:capture` / `pg:dump` and read your config var names. - A domain you control, with the ability to point its DNS at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## Phase 1 — inventory your app (read-only) Before anything is created or billed, have your assistant build a complete picture of what it's migrating. This phase is read-only on both sides — it reads your repo and lists American Cloud options without touching your Heroku app or your account. Open your project in Claude Code and paste: ```text This is a Heroku app I want to migrate to a server I own. Take inventory first — don't create anything yet: 1. Read the Procfile and list every process type (web, worker, release, anything else) and the exact command each one runs. 2. Detect the runtime and version: check for a Gemfile / package.json / requirements.txt / runtime.txt and tell me the language and version the app expects, plus any system packages it implies (image libs, a JS build step, etc.). 3. If there's an app.json, read it and list the addons and env declarations it names. 4. List the NAMES of the config vars the app reads from the environment (grep the code for env lookups). Do NOT ask me for their values — I'll set those on the server myself. 5. Tell me which backing services this app needs: Postgres? Redis? anything else? Then summarize it back to me as a migration target: how many services I'll run, what runtime to install, and what to install for the database and cache. ``` ### What your assistant will do This phase is your assistant reading files — your local repo and, through the MCP server, your American Cloud options: 1. **Read the `Procfile`.** Each line becomes one service to recreate. A typical Rails app has `web: bundle exec puma -C config/puma.rb` and `worker: bundle exec sidekiq` — two services. A `release:` line is a one-shot migration command to run on each deploy, not a long-running service. 2. **Identify the runtime from the manifest.** A `Gemfile` plus `.ruby-version` means Ruby; `package.json` means Node; `requirements.txt` or `pyproject.toml` means Python. This is what replaces the buildpack — instead of Heroku auto-detecting, your assistant installs that exact runtime on the VM. 3. **Read `app.json` if present.** Heroku's `app.json` often declares the addons (`heroku-postgresql`, `heroku-redis`) and the env vars the app expects — a ready-made checklist of what to stand up. 4. **Collect config var *names*.** It greps your code for environment lookups (`ENV[...]`, `process.env.*`, `os.environ[...]`) so the server's environment file has every key the app reads — without ever needing the secret values. **Never paste secret config var values into the chat.** Your assistant only needs the *names* of your config vars to build the environment file's structure. Put the real values — database passwords, API keys, `SECRET_KEY_BASE` — directly into the server's env file over SSH, where they stay on the box you own. Treat them like any other secret: not in the conversation, not in the repo. ## Phase 2 — plan and price (read-only) With the inventory in hand, ask for a sized plan and a cost estimate. This is still read-only — cost estimates create nothing. ```text Based on that inventory, plan the American Cloud side. List the available regions and current Ubuntu images and the VM packages. Recommend ONE VM size that comfortably runs the web process, the worker process, PostgreSQL, and Redis together, with headroom for my database size. Show me the monthly cost estimate before I approve anything, so I can compare it to my Heroku bill. ``` **What your assistant will do:** 1. Call `list_regions`, `list_images` (filtered to Ubuntu), and `list_vm_packages` to find a region near you, a current Ubuntu LTS image, and a compute tier whose CPU/memory/disk limits fit your workload. 2. Call `get_cost_estimate_vm` with that exact region, package, size, and image, and show you the **hourly and monthly numbers before creating anything**. Nothing is billed yet. 3. Hand you a side-by-side: one VM running everything versus the stack of Heroku dynos and add-ons you're paying for today. You bring your Heroku bill; the assistant brings the American Cloud estimate. Because your web, worker, database, and cache all share one machine, you're sizing one server instead of renting four metered products. Need more later? `scale_vm` resizes it in place. ## Phase 3 — provision and deploy Now the writes begin. This is the build prompt — paste it after you've approved the plan and cost from Phase 2. Read each step's output before approving the next. ```text Go ahead and build the new home for this app. Walk through it step by step and wait for my confirmation on anything that costs money: 1. Check whether I have an SSH key registered; if not, create one and tell me where the private key is saved. 2. Create the Ubuntu VM we sized, on an isolated network, with that SSH key, and open inbound ports 22, 80, and 443. 3. Over SSH, install the runtime from my manifest (the exact language version), plus the system packages the app needs, PostgreSQL, and Redis. Keep both PostgreSQL and Redis listening on localhost only. 4. Clone this repo onto the VM and install dependencies. 5. Create the app's environment file from the config var NAMES we found, with placeholder values — I'll fill in the real secrets myself afterward. Point DATABASE_URL and REDIS_URL at the local PostgreSQL and Redis. 6. Turn each Procfile process into its own systemd service that reads that environment file, restarts on crash, and starts on boot. Put nginx in front of the web service as a reverse proxy on port 80. 7. Turn any Heroku Scheduler jobs into cron entries. Don't start the app against real data yet — we'll migrate the database next. ``` **What your assistant will do:** 1. **Sort out the SSH key.** It calls `list_ssh_keys`; if nothing fits, `create_ssh_key` generates a pair — the private key is returned once and never stored, so the assistant saves it locally and sets the right permissions. It needs this key to install on the VM and to SSH in afterward. 2. **Create the server.** On your go-ahead, `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess` to open ports 22, 80, and 443 on the network's public IP, and `keypairs` to install your key. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` and it has a public IP. 3. **Install the stack over SSH.** It installs the exact runtime your manifest declares (this is the buildpack's job, done explicitly), the system packages your app needs, then PostgreSQL and Redis — both bound to `localhost` so neither is exposed to the internet. Nothing new opens on the firewall for them. 4. **Lay down the environment file.** It writes one env file keyed by every config var name from Phase 1, with placeholders, and sets `DATABASE_URL` / `REDIS_URL` to the local services. You fill in the real secret values over SSH after this step. 5. **Recreate the processes.** Each `Procfile` line becomes a `systemd` unit reading that env file — `web` and `worker` each get one, restarting on crash and on boot. nginx reverse-proxies the public ports to the web process. A `release:` command becomes the migration step your deploy runs. 6. **Schedule the jobs.** Heroku Scheduler entries become `cron` jobs on the VM. Tell the assistant to **explain each step before it runs it** if you want to follow along — *"narrate what you're about to do and why."* Destructive operations are flagged regardless, and clients that support confirmations prompt you before anything irreversible. ## Phase 4 — migrate the data This is the only phase with real downtime, so it's deliberately last and deliberately careful. The goal is a clean cutover: freeze writes on Heroku, take a final dump, restore it on the VM, and verify nothing was lost. ```text Now migrate the database with minimal downtime: 1. Put the Heroku app in maintenance mode so nothing writes to the database while we copy it. 2. Take a final pg_dump of the Heroku Postgres database (custom format). 3. Copy the dump to the VM and pg_restore it into the local PostgreSQL. 4. Run the app's release/migration command against the restored database. 5. Verify the migration: compare row counts on the main tables between the Heroku database and the restored one, and flag any mismatch. 6. Start the systemd services and confirm the app responds locally on the VM (curl the health endpoint through nginx). Report the row-count comparison and the local health check before we touch DNS. ``` **What your assistant will do:** 1. **Freeze writes.** It enables Heroku maintenance mode so the live app stops writing mid-copy — the dump is a consistent point-in-time snapshot. 2. **Take the final dump.** A `pg_dump` in custom format captures the schema and data. 3. **Restore on the VM.** It copies the dump over and runs `pg_restore` into the local PostgreSQL you installed in Phase 3. 4. **Run migrations.** Your `release:` command (e.g. `rails db:migrate`) runs against the restored database so the schema matches the code being deployed. 5. **Verify counts.** It compares row counts on your key tables between source and target and surfaces any difference — your proof the data arrived intact before you commit to the cutover. 6. **Smoke-test locally.** It starts the services and curls the app through nginx *on the VM itself*, confirming the stack works end to end before any public traffic hits it. Redis is usually a cache or a job queue, not a system of record, so it rarely needs a data copy — a fresh Redis is fine, and the worker repopulates it. If yours holds data you can't lose, tell the assistant and it'll dump and restore Redis the same way. ## Phase 5 — DNS cutover and HTTPS With the app verified on the VM, point your domain at it and switch on TLS. ```text Cut my domain {your-domain.com} over to the new VM: 1. Check whether the domain is already a hosted DNS zone here; if not, create it and tell me the nameservers to set at my registrar. 2. Lower the TTL first if it's high, then point the A record at the VM's public IP. 3. Once DNS resolves to the VM, provision a Let's Encrypt certificate with certbot and switch nginx to HTTPS with auto-renewal. Leave the Heroku app in maintenance mode — anyone still on cached DNS should see the maintenance page, not write to the old database. Tell me when https://{your-domain.com} is live and served from the new server. ``` **What your assistant will do:** 1. Call `list_dns_zones`; if your domain isn't hosted here, `create_dns_zone` adds it and the assistant shows you the American Cloud nameservers to set at your registrar. 2. Call `create_dns_record` to add (or update) the `A` record pointing your domain at the VM's public IP. Lowering the TTL beforehand shortens the cutover window. 3. Once DNS resolves to the VM, run certbot for a Let's Encrypt certificate, reconfigure nginx for port 443, and enable automatic renewal. **The Heroku app stays in maintenance mode from the final dump until you decommission it.** While DNS propagates, some visitors still resolve to Heroku — in maintenance mode they see a holding page instead of silently reading and writing the *old* database. Switching it back on during propagation is how migrations lose data. DNS changes take time to propagate — from a few minutes to a couple of hours, depending on your registrar and the record's TTL. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* certbot also needs DNS to resolve to the VM before it can issue the certificate. ## Phase 6 — verify, then decommission Run on the new server for a day or two before you delete anything on Heroku. Keep the Heroku app around — it's your rollback if something surfaces under real traffic. ```text The app's been live on the VM for a couple of days and looks healthy. Walk me through decommissioning Heroku safely: confirm the VM is the only thing serving the domain, remind me to download a final Heroku database backup to keep offline, and give me the Heroku CLI commands to scale the dynos to zero and then delete the app and its add-ons once I'm sure. ``` The assistant can confirm the American Cloud side — the VM is `STARTED`, the services are running, the certificate is valid — but the actual Heroku teardown stays in your hands: download one last backup to keep offline, scale the dynos to zero, then delete the app and its add-ons when you're confident. From here, every future deploy is a push-and-restart on a server you own. ## Follow-up: a one-prompt deploy command The migration is the hard part. Make every future deploy trivial: ```text Set up a deploy script in this repo that ships updates to the VM: push the latest committed code over SSH, install dependencies, run the release/migration command, and restart the web and worker systemd services. Add a "deploy" entry to my package.json or a Rake task, and document the one command I run from now on. ``` After this, shipping a change is *"run the deploy script"* — or just *"deploy the latest"* and the assistant runs it. ## Troubleshooting **A service won't start after migration.** Ask your assistant to *"show me the journalctl logs for the web (or worker) service and tell me what's failing."* The usual culprit is a missing or placeholder value in the environment file — confirm every config var name from Phase 1 has its real value set on the server. **The app can't reach the database.** Have the assistant confirm PostgreSQL is running and that `DATABASE_URL` in the env file points at `localhost` with the right database and user. Since Postgres listens only on `localhost`, nothing on the firewall needs to change — connections stay on the box. **The site is unreachable on 80 or 443.** Ask your assistant to *"list the firewall rules on the VM's public IP and confirm 80 and 443 are open."* It can call `list_firewall_rules` and add any missing rule with `create_firewall_rule`. Have it also check the VM is `STARTED` with `get_vm` and that nginx and the web service are both running. **SSH connection refused.** Confirm port 22 is open (same `list_firewall_rules` check) and that the private key from the `create_ssh_key` step is the one your assistant is using. If the key was lost, the assistant can reset access with `reset_vm_password` or open a browser console session with `create_vm_console`. **Row counts don't match in Phase 4.** Don't cut DNS over. Ask the assistant to re-run the dump and restore — the most common cause is a write that slipped in before maintenance mode took effect. Re-freezing and re-dumping gives a clean snapshot. ## Next steps - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, networking, and DNS - [Use American Cloud with Claude Code](/docs/mcp/claude-code) — the provision-and-deploy client setup - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — the same VM-plus-systemd pattern, start to finish - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — move user uploads and backups off the dyno filesystem and store them durably - [Run Kubernetes with your AI assistant](/docs/deploy-with-ai/kubernetes) — when one VM isn't enough - [Teach your AI agent to deploy here](/docs/deploy-with-ai/agents-md) — add one file to your repo and your agent knows this whole playbook ## Migrate from DigitalOcean If you run droplets on DigitalOcean, moving to American Cloud is the most mechanical migration there is. The mental model is the same — a Linux server with a public IP, a block volume, a firewall, a DNS record — and almost everything maps one-to-one. So this recipe hands the labor to your AI assistant: with the [American Cloud MCP server](/docs/mcp/overview) connected, it inventories what you have, prices the American Cloud equivalent, provisions it, syncs your data, and cuts DNS over — from prompts you paste in. ## How the migration actually works Disk images don't transfer between clouds. There's no "import this droplet" button, on any provider, because a droplet's image is tied to DigitalOcean's hypervisor and metadata. Trying to lift a raw image across is the slow, fragile path. The reliable path is **provision and sync**, and it's exactly what your assistant is good at: 1. It looks at the source droplet — over SSH, read-only — to see what's installed and how it's configured. 2. It creates a matching American Cloud VM (same CPU/RAM class, same OS). 3. It replicates the software setup on the new VM. 4. It `rsync`s your application data and files across. 5. It replicates your firewall rules. 6. It cuts DNS over to the new IP. You end up with a clean, current server running your software on your data — not a copy of an aging disk image with years of drift baked in. Provisioning and data sync are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety. Start with a read-only key for the inventory phase, then switch when you're ready to build. ## What maps to what Every DigitalOcean primitive has a direct American Cloud equivalent: | On DigitalOcean | On American Cloud | How it moves | |---|---|---| | Droplet | VM (like-for-like CPU/RAM) | New VM provisioned, software replicated, data `rsync`ed | | Block storage volume | Block storage volume | New volume created and attached; data copied | | Spaces (object storage) | Object storage (S3-compatible) | `rclone` syncs bucket-to-bucket directly | | DigitalOcean DNS | Hosted DNS zones and records | Zone and records recreated, then cut over | | Cloud firewalls | Firewall rules | Inbound rules replicated per public IP | | Reserved IPs | Public IPs | Reserved on the new network, mapped to the VM | | DOKS (managed Kubernetes) | Managed Kubernetes | New cluster, workloads re-applied — see [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) | | Managed databases | Database on a VM | PostgreSQL / MySQL / Redis installed on a VM, migrated with dump/restore | Both object storage services are S3-compatible, which is why Spaces is the easiest piece of all — `rclone` copies straight from one to the other with no intermediate download. And a managed database becomes a database your assistant installs and runs on a VM, migrated with a standard dump and restore. ## Before you start - SSH access to each droplet you want to move (the assistant inspects them read-only). - A domain you control, with the ability to change its DNS or nameservers. - The MCP server connected with a read-write key and `--allow-writes`. - Optional: `doctl` (DigitalOcean's CLI) authenticated locally, so the assistant can read your DigitalOcean inventory directly. If you'd rather not install it, just describe what you have and the assistant works from that plus what it finds over SSH. [Claude Code](/docs/mcp/claude-code) is the ideal client here, because migrating a droplet means running commands *on* both servers — SSH in, install packages, `rsync` files. Claude Code combines the American Cloud tools with your terminal in one session. Other [MCP clients](/docs/mcp/overview) handle the provisioning fine; you'll just run the SSH and `rsync` steps yourself when the assistant tells you to. ## Phase 1: inventory and plan Start read-only. The goal is a complete picture of what's on DigitalOcean and a priced American Cloud plan for each piece — before you create anything. ```text I'm migrating from DigitalOcean to American Cloud. Help me inventory and plan it. Don't create anything yet — this is a read-only planning pass. 1. Take stock of what I have on DigitalOcean. If doctl is available, list my droplets, volumes, Spaces, reserved IPs, cloud firewalls, and DNS domains. Otherwise, ask me for the list. For each droplet, note its region, vCPU/RAM, OS, and attached storage. 2. For each droplet I can SSH into, connect read-only and tell me what's actually installed and running: the OS version, the web server, the runtime (Node, Python, PHP, etc.), any database engine, and where the application data lives on disk. 3. Map each DigitalOcean resource to its American Cloud equivalent. For the VMs, list American Cloud regions and VM packages and pick the closest like-for-like CPU/RAM match for each droplet. 4. Price the American Cloud side: a per-droplet cost estimate for each VM, plus block storage and object storage. Give me a total monthly estimate. 5. Produce a migration plan: which droplet to move first (smallest/lowest risk), the order of the rest, and where a managed database needs to become a database on a VM. ``` ### What your assistant will do 1. **Read your DigitalOcean inventory.** If `doctl` is authenticated, it runs read-only `doctl` commands to enumerate droplets, volumes, Spaces, reserved IPs, firewalls, and domains. Otherwise it works from your description. 2. **Inspect each droplet over SSH.** It connects read-only and checks the OS, the running services, the installed runtimes and database engines, and where your data lives — so the new server is built to match, not guessed at. 3. **Map to American Cloud equivalents.** It calls `list_regions`, `list_vm_packages`, and `list_images` to find a nearby region, the closest CPU/RAM tier for each droplet, and a matching OS image. 4. **Price every piece.** It calls `get_cost_estimate_vm` per droplet, `get_cost_estimate_block_storage` for volumes, and `get_cost_estimate_object_storage` for Spaces replacements — and totals them. Nothing is billed during planning. 5. **Sequence the move.** It recommends starting with the smallest, lowest-risk droplet so you build confidence on something easy, and flags any managed database that needs to become a database on a VM. ## Phase 2: migrate one droplet This is the repeatable unit. Run it once per droplet — start with the small one from your plan, then re-run for each remaining server. Fill in the placeholders. ```text Migrate the DigitalOcean droplet "\{droplet-name\}" to American Cloud, using the like-for-like size we picked in the plan. Walk through it step by step and show me the cost estimate before creating anything. 1. Show me the monthly cost estimate for the matching VM and any block storage. Wait for me to confirm. 2. Create the American Cloud VM with that size and a matching Ubuntu image, on an isolated network, using my SSH key. If the droplet had a block volume, create and attach a matching one. Wait until the VM is fully running and has a public IP. 3. Replicate the firewall: read the inbound rules protecting the droplet and create the equivalent firewall rules on the new VM's public IP (same ports, same source ranges). Whitelist only what the droplet allowed. 4. Replicate the software setup over SSH: install the same web server, runtime, and packages the droplet runs, matching versions where it matters. 5. If the droplet uses a managed database, install the same engine (PostgreSQL / MySQL / Redis) on the new VM, keep it listening on localhost only, and migrate the data with a dump from the source and a restore on the target. 6. Do an INITIAL data sync now, while the droplet keeps serving traffic: rsync the application files and any volume data from the droplet to the new VM. 7. Bring the app up on the new VM and test it against its public IP directly (curl with a Host header, or by editing my local hosts file) — do NOT touch DNS yet. Confirm it works end to end. Stop after the test and tell me what to verify before we cut over. ``` ### What your assistant will do 1. **Price, then provision.** It shows you `get_cost_estimate_vm` (and `get_cost_estimate_block_storage` if there's a volume) and waits. On your go-ahead, `create_vm` provisions the VM on an isolated network with your SSH key installed via `keypairs`, and `networkAccess` opens the ports the app needs. It polls `get_vm` until the status reaches `STARTED` and a public IP is assigned. 2. **Match the storage.** If the droplet had a block volume, `create_block_storage_volume` makes a matching one and `attach_block_storage_volume` attaches it to the new VM in the same region. 3. **Replicate the firewall.** It reads the droplet's inbound rules and recreates them on the new VM's public IP with `create_firewall_rule` — same protocols, same ports, same source CIDRs. It whitelists only the sources the droplet allowed; nothing is opened to the whole internet unless the droplet already was. 4. **Rebuild the software.** Over SSH it installs the same stack it found during inventory — web server, runtime, packages — and lays down your config. 5. **Move the database, if any.** For a managed database, it installs the matching engine on the VM, binds it to `localhost` so it isn't exposed, and migrates the data with a dump/restore. The connection string in your app points at `localhost`, and nothing new is opened on the firewall. 6. **Sync the data.** It `rsync`s your application files and volume data from the droplet to the new VM while the droplet stays live. 7. **Test against the new IP.** It brings the app up and verifies it against the new VM's public IP directly — without changing any DNS — so you confirm the new server works before a single user is routed to it. **Two `rsync` passes keep downtime to minutes.** The first pass copies the bulk of your data while the droplet keeps serving traffic — it can take a while, but nobody notices. At cutover you briefly stop writes on the source and run a *second* `rsync`, which only transfers what changed since the first pass and finishes in seconds to minutes. That turns hours of copy time into a short write-freeze. Ask your assistant to *"do the final delta sync now"* right before you flip DNS. ## Phase 3: cut over and decommission Once the new VM passes its direct-IP test, the switch itself is small. Do it per droplet, or batch the DNS changes once all droplets are tested. ```text The new VM for "\{droplet-name\}" tested clean. Cut DNS over to it. 1. First, lower the TTL on the affected DNS records to something short (e.g. 300 seconds) and wait for the old TTL to expire, so the cutover propagates fast. 2. Do a final delta rsync from the droplet, with writes briefly paused, so the new VM has the latest data. 3. Update the DNS records to point at the new VM's public IP. If I want a stable address, reserve a public IP on American Cloud and map it to the VM first, then point DNS at that. 4. Tell me how to confirm the domain now resolves to the new VM, and keep the old droplet running until I've verified everything for a day or two. ``` ### What your assistant will do 1. **Pre-lower the TTL — wherever DNS is served today.** If the domain already lives on American Cloud DNS, the assistant shortens the relevant records with `update_dns_record`. If it's still on DigitalOcean DNS or elsewhere, that's where the TTL must drop (the assistant tells you exactly what to change), and if you're also moving the zone here, `create_dns_zone` adds it and the assistant shows you the nameservers to set at your registrar — a delegation change that takes time on its own, so do it well before cutover. 2. **Final delta sync.** With writes briefly paused on the source, it runs the second `rsync` — only the changes since the initial pass — so the cutover loses no data. 3. **Flip the records.** It points the `A` records at the new VM's public IP with `update_dns_record`. For a stable address it can `reserve_public_ip` on the new network (the equivalent of a DigitalOcean reserved IP) and map it to the VM with `enable_static_nat`, then point DNS at that. 4. **Run both briefly, then retire.** It leaves the droplet running so a rollback is just pointing the record back — minutes, thanks to the lowered TTL. After a day or two of clean operation, you destroy the source on the DigitalOcean side and stop paying for it. ## Migrating Spaces (object storage) Because both services are S3-compatible, your Spaces buckets are the simplest piece to move — `rclone` copies directly from one to the other without downloading anything to your machine in between. ```text Migrate my DigitalOcean Spaces to American Cloud object storage. 1. Create an American Cloud object storage unit and the buckets I need, and give me the S3 access keys and endpoint. 2. Set up rclone with two remotes — my DigitalOcean Spaces and the new American Cloud unit — and copy each bucket across, server to server. 3. Update my app's S3 endpoint and credentials to point at American Cloud. ``` Your assistant calls `create_object_storage_unit` and `create_object_storage_bucket`, then `get_object_storage_keys` to retrieve the S3 access key, secret, and endpoint. It configures `rclone` with both providers as S3-compatible remotes and runs `rclone copy` directly between them. American Cloud object storage has **no egress fees**, so accessing your migrated data costs nothing per gigabyte (see [why egress fees matter](/blog/egress-fees-explained)). For the full S3 toolkit — the AWS CLI, `s3cmd`, framework upload libraries — see [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) and the [s3cmd guide](/docs/tutorials/s3cmd-simple-storage-service-command-line-tool-and). ## Migrating DOKS (managed Kubernetes) If you run DigitalOcean Kubernetes, your assistant can stand up a managed cluster on American Cloud and you re-apply your workloads onto it. The full walkthrough — sizing, creating the cluster, fetching the kubeconfig, and deploying — is in [Run on Kubernetes](/docs/deploy-with-ai/kubernetes). The migration shape is the same provision-and-sync idea: create the cluster, point `kubectl` at it, apply your manifests, migrate any persistent data, then move DNS. ## Tips for a smooth move - **Start small.** Move the lowest-risk droplet first. By the time you reach the important ones, the playbook is muscle memory and your assistant has the pattern down. - **Keep the source until you're sure.** Running both for a day or two is cheap insurance and makes rollback a non-event. Destroy the droplet only after the new VM has proven itself. - **Always price before you build.** Make *"show me the cost estimate first"* part of every prompt. The assistant has cost-estimate tools for VMs, block storage, and object storage — there's no reason to create blind. - **Let the assistant read, not guess.** The SSH inspection step is what makes the new server match the old one. Don't skip it; an accurate inventory is the difference between a clean rebuild and a debugging session. ## Next steps - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, networking, storage, and DNS - [Use American Cloud with Claude Code](/docs/mcp/claude-code) — the provision-and-deploy client setup - [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — the full single-server build, end to end - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — the S3-compatible details for your Spaces move - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — for your DOKS workloads - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your deploy conventions so future moves are one prompt ## Migrate from Linode A Linode instance is a Linux server with a public IP, a block volume, a firewall, and a DNS record pointed at it — which is exactly what makes moving off it to American Cloud so mechanical. Almost every piece maps one-to-one, so this recipe hands the work to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, it takes inventory of what you run on Linode, prices the American Cloud equivalent, provisions it, syncs your data, and cuts DNS over — all from prompts you paste in. (Linode is now part of Akamai; if that change is part of why you're looking around, this is the path across.) ## How the migration actually works Disk images don't move between clouds. There's no "import this Linode" button, because an instance's image is tied to Linode's hypervisor and metadata — and trying to drag a raw image across is the slow, brittle option even when it's possible. The reliable path is **provision and sync**, and it plays to exactly what your assistant is good at: 1. It inspects the source instance — over SSH, read-only — to learn what's installed and how it's set up. 2. It creates a matching American Cloud VM (same vCPU/RAM class, same OS). 3. It rebuilds the software stack on the new VM. 4. It `rsync`s your application data and files across. 5. It recreates your firewall and any inbound port rules. 6. It cuts DNS over to the new IP. What you get is a clean, current server running your software on your data — not a clone of an aging image with years of configuration drift baked in. Provisioning and data sync are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety. Use a read-only key for the inventory phase, then switch when you're ready to build. ## What maps to what Every Linode primitive has a direct American Cloud equivalent: | On Linode (Akamai) | On American Cloud | How it moves | |---|---|---| | Linode instance | VM (like-for-like vCPU/RAM) | New VM provisioned, software rebuilt, data `rsync`ed | | Block Storage Volume | Block storage volume | New volume created and attached; data copied | | Object Storage | Object storage (S3-compatible) | `rclone` syncs bucket-to-bucket directly | | Linode DNS | Hosted DNS zones and records | Zone and records recreated, then cut over | | Cloud Firewalls | Firewall rules (+ port forwarding) | Inbound rules replicated per public IP | | NodeBalancers | Load balancer rules | Rule recreated, backend VMs assigned — see [Load balancing with your AI assistant](/docs/deploy-with-ai/load-balancer) | | LKE (managed Kubernetes) | Managed Kubernetes | New cluster, workloads re-applied — see [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) | | Managed Databases | Database on a VM | PostgreSQL / MySQL installed on a VM, migrated with dump/restore | Both object storage services are S3-compatible, which makes Object Storage the easiest piece of all — `rclone` copies straight from one to the other with no download in between. Object storage on American Cloud is for uploads, assets, backups, and artifacts. A Managed Database becomes a database engine your assistant installs and runs on a VM, migrated with a standard dump and restore. ## Before you start - SSH access to each instance you want to move (the assistant inspects them read-only). - A domain you control, with the ability to change its DNS records or nameservers. - The MCP server connected with a read-write key and `--allow-writes`. - Optional: `linode-cli` authenticated locally, so the assistant can read your Linode inventory directly. If you'd rather not install it, just describe what you run and the assistant works from that plus what it finds over SSH. [Claude Code](/docs/mcp/claude-code) is the ideal client here, because migrating an instance means running commands *on* both servers — SSH in, install packages, `rsync` files. Claude Code combines the American Cloud tools with your terminal in one session. Other [MCP clients](/docs/mcp/overview) handle the provisioning fine; you'll just run the SSH and `rsync` steps yourself when the assistant tells you to. ## Phase 1: inventory and plan Start read-only. The goal is a full picture of what's on Linode and a priced American Cloud plan for each piece — before you create anything. ```text I'm migrating from Linode to American Cloud. Help me inventory and plan it. Don't create anything yet — this is a read-only planning pass. 1. Take stock of what I run on Linode. If linode-cli is available, list my instances, Block Storage Volumes, Object Storage buckets, NodeBalancers, Cloud Firewalls, and DNS domains. Otherwise, ask me for the list. For each instance, note its region, vCPU/RAM, OS, and attached storage. 2. For each instance I can SSH into, connect read-only and tell me what's actually installed and running: the OS version, the web server, the runtime (Node, Python, PHP, etc.), any database engine, and where the application data lives on disk. 3. Map each Linode resource to its American Cloud equivalent. For the VMs, list American Cloud regions and VM packages and pick the closest like-for-like vCPU/RAM match for each instance. 4. Price the American Cloud side: a per-instance cost estimate for each VM, plus block storage and object storage. Give me a total monthly estimate so I can set it next to my current Linode bill. 5. Produce a migration plan: which instance to move first (smallest/lowest risk), the order of the rest, and where a Managed Database needs to become a database on a VM. ``` ### What your assistant will do 1. **Read your Linode inventory.** If `linode-cli` is authenticated, it runs read-only commands to enumerate instances, volumes, Object Storage buckets, NodeBalancers, firewalls, and domains. Otherwise it works from your description. 2. **Inspect each instance over SSH.** It connects read-only and checks the OS, the running services, the installed runtimes and database engines, and where your data lives — so the new server is built to match, not guessed at. 3. **Map to American Cloud equivalents.** It calls `list_regions`, `list_vm_packages`, and `list_images` to find a nearby region, the closest vCPU/RAM tier for each instance, and a matching OS image. 4. **Price every piece.** It calls `get_cost_estimate_vm` per instance, `get_cost_estimate_block_storage` for volumes, and `get_cost_estimate_object_storage` for the Object Storage replacement — and totals them so you can compare against your own Linode bill. Nothing is billed during planning. 5. **Sequence the move.** It recommends starting with the smallest, lowest-risk instance so you build confidence on something easy, and flags any Managed Database that needs to become a database on a VM. ## Phase 2: migrate one instance This is the repeatable unit. Run it once per instance — start with the small one from your plan, then re-run for each remaining server. Fill in the placeholders. ```text Migrate the Linode instance "{instance-name}" to American Cloud, using the like-for-like size we picked in the plan. Walk through it step by step and show me the cost estimate before creating anything. 1. Show me the monthly cost estimate for the matching VM and any block storage. Wait for me to confirm. 2. Create the American Cloud VM with that size and a matching Ubuntu image, on an isolated network, using my SSH key. Open port 22 plus ONLY the ports the app actually serves (e.g. 80 and 443), restricted to the right sources. If the instance had a Block Storage Volume, create and attach a matching one. Wait until the VM is fully running and has a public IP. 3. Rebuild the software setup over SSH: install the same web server, runtime, and packages the instance runs, matching versions where it matters, and lay down my config. 4. If the instance uses a Managed Database, install the same engine (PostgreSQL / MySQL) on the new VM, keep it listening on localhost only, and migrate the data with a dump from the source and a restore on the target. 5. Do an INITIAL data sync now, while the instance keeps serving traffic: rsync the application files and any volume data from the instance to the new VM. 6. Bring the app up on the new VM and test it against its public IP directly (curl with a Host header, or by editing my local hosts file) — do NOT touch DNS yet. Confirm it works end to end. Stop after the test and tell me what to verify before we cut over. ``` ### What your assistant will do 1. **Price, then provision.** It shows you `get_cost_estimate_vm` (and `get_cost_estimate_block_storage` if there's a volume) and waits. On your go-ahead, `create_vm` provisions the VM on an isolated network with your SSH key installed via `keypairs`. Port 22 (so it can SSH in for the rebuild) and the ports your app serves are opened through `networkAccess.inboundPorts`, which sets up the firewall rule **and** the port forwarding together so each port is actually reachable — a firewall rule on its own wouldn't be. It polls `get_vm` until the status reaches `STARTED` and a public IP is assigned. 2. **Match the storage.** If the instance had a Block Storage Volume, `create_block_storage_volume` makes a matching one and `attach_block_storage_volume` attaches it to the new VM in the same region. 3. **Rebuild the software.** Over SSH it installs the same stack it found during inventory — web server, runtime, packages — and applies your config. 4. **Move the database, if any.** For a Managed Database, it installs the matching engine on the VM, binds it to `localhost` so it isn't exposed, and migrates the data with a dump/restore. Your app's connection string points at `localhost`, and nothing new is opened on the firewall. 5. **Sync the data.** It `rsync`s your application files and volume data from the instance to the new VM while the source stays live. 6. **Test against the new IP.** It brings the app up and verifies it against the new VM's public IP directly — without changing any DNS — so you confirm the new server works before a single user is routed to it. **Need to open more ports later?** When you adjust access *after* the VM exists — say you add an API port — a firewall rule alone won't make it reachable. Ask your assistant to add **both** the firewall rule (`create_firewall_rule`) **and** the port forwarding rule (`create_port_forwarding_rule`), or to map the public IP straight to the VM with `enable_static_nat`. Opening the firewall without forwarding the port is the classic "rule looks right, traffic still doesn't arrive" trap. **Two `rsync` passes keep downtime to minutes.** The first pass copies the bulk of your data while the instance keeps serving traffic — it can take a while, but nobody notices. At cutover you briefly stop writes on the source and run a *second* `rsync`, which only transfers what changed since the first pass and finishes in seconds to minutes. That turns hours of copy time into a short write-freeze. Ask your assistant to *"do the final delta sync now"* right before you flip DNS. ## Phase 3: cut over and decommission Once the new VM passes its direct-IP test, the switch itself is small. Do it per instance, or batch the DNS changes once all instances are tested. ```text The new VM for "{instance-name}" tested clean. Cut DNS over to it. 1. First, lower the TTL on the affected DNS records at whichever host serves the domain today (Linode DNS, or my registrar), and wait for the old TTL to expire — so the cutover propagates fast. Tell me exactly what to change there. 2. If the database is involved, put the source app into maintenance / freeze writes now and keep it frozen until I decommission — do NOT bring it back up during propagation. 3. Do a final delta rsync from the instance so the new VM has the latest data. 4. Update the DNS records to point at the new VM's public IP. If I want a stable address, reserve a public IP on American Cloud and map it to the VM first, then point DNS at that. 5. Tell me how to confirm the domain now resolves to the new VM, and keep the old instance running until I've verified everything for a day or two. ``` ### What your assistant will do 1. **Pre-lower the TTL — wherever DNS is served today.** TTLs have to drop at the host that currently answers for your domain. If that's Linode DNS or your registrar, the assistant tells you exactly which records to shorten there; it can't shorten a TTL on a host it doesn't manage. If the zone already lives on American Cloud DNS, it shortens the records with `update_dns_record`. And if you're *moving* the zone here, `create_dns_zone` adds it and the assistant shows you the nameservers to set at your registrar — a delegation change that propagates on its own clock, so do it well ahead of cutover and create the new records with short TTLs. 2. **Hold the source still.** If a database is in play, the source app goes into maintenance / write-freeze at the final dump and stays frozen until you decommission. It is not brought back up during propagation, so no writes are stranded on the old server while DNS is still pointing some clients at it. 3. **Final delta sync.** With writes paused on the source, it runs the second `rsync` — only the changes since the initial pass — so the cutover loses no data. 4. **Flip the records.** It points the `A` records at the new VM's public IP with `update_dns_record`. For a stable address it can `reserve_public_ip` on the new network and map it to the VM with `enable_static_nat`, then point DNS at that. 5. **Run both briefly, then retire.** It leaves the instance running so you can roll back instantly if anything's off. After a day or two of clean operation, you delete the source on the Linode side and stop paying for it. ## Migrating Object Storage Because both services are S3-compatible, your Object Storage buckets are the simplest piece to move — `rclone` copies directly from one to the other without downloading anything to your machine in between. ```text Migrate my Linode Object Storage to American Cloud object storage. 1. Create an American Cloud object storage unit and the buckets I need, and give me the S3 access keys and endpoint. 2. Set up rclone with two remotes — my Linode Object Storage and the new American Cloud unit — and copy each bucket across, server to server. 3. Update my app's S3 endpoint and credentials to point at American Cloud. ``` Your assistant calls `create_object_storage_unit` and `create_object_storage_bucket`, then `get_object_storage_keys` to retrieve the S3 access key, secret, and endpoint. It configures `rclone` with both providers as S3-compatible remotes and runs `rclone copy` directly between them. American Cloud object storage has **no egress fees**, so accessing your migrated data costs nothing per gigabyte (see [why egress fees matter](/blog/egress-fees-explained)). For the full S3 toolkit — the AWS CLI, `s3cmd`, framework upload libraries — see [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage). ## Migrating NodeBalancers If a NodeBalancer fronts a pool of instances, the equivalent is a load balancer rule with your migrated VMs assigned as backends. Your assistant reserves a public IP, creates the rule with `create_load_balancer_rule` (same public/backend ports and algorithm), and assigns the new VMs with `assign_vms_to_load_balancer`. The full walkthrough — algorithms, health, and assigning backends — is in [Load balancing with your AI assistant](/docs/deploy-with-ai/load-balancer). ## Migrating LKE (managed Kubernetes) If you run Linode Kubernetes Engine, your assistant can stand up a managed cluster on American Cloud and you re-apply your workloads onto it. The full walkthrough — sizing, creating the cluster, fetching the kubeconfig, and deploying — is in [Run on Kubernetes](/docs/deploy-with-ai/kubernetes). The migration shape is the same provision-and-sync idea: create the cluster, point `kubectl` at it, apply your manifests, migrate any persistent data, then move DNS. ## Backups parity Linode Backups were tied to your instances; on American Cloud the equivalent is a snapshot of the VM volume plus a periodic dump pushed to object storage. Your assistant can take a snapshot with `create_snapshot` after the migration settles, and set up a scheduled database/file dump that uploads to a bucket — so you keep the same "I can roll back" safety net without the source instance. See [Backups with your AI assistant](/docs/deploy-with-ai/backups) for the full pattern. ## Tips for a smooth move - **Start small.** Move the lowest-risk instance first — a clean rehearsal on something unimportant teaches you and the assistant the rhythm before anything critical moves. - **Keep the source until you're sure.** A few extra days of Linode billing buys an instant rollback path. Delete the instance only after the new VM has proven itself under real traffic. - **Always price before you build.** Make *"show me the cost estimate first"* part of every prompt, and set the assistant's estimate next to your real Linode bill. There's no reason to create blind. - **Let the assistant read, not guess.** The SSH inspection step is what makes the new server match the old one. Don't skip it; an accurate inventory is the difference between a clean rebuild and a debugging session. ## Next steps - [Load balancing with your AI assistant](/docs/deploy-with-ai/load-balancer) — for your NodeBalancer pools - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — for your LKE workloads - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — the S3-compatible details for your Object Storage move - [Backups with your AI assistant](/docs/deploy-with-ai/backups) — snapshots plus object-storage dumps for backup parity - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — teach your assistant your deploy conventions so future moves are one prompt ## Migrate from Render Render made shipping a service as simple as connecting a repo, and the per-service model made the bill grow one row at a time. A real app on Render is rarely one service: it's a web service, maybe a background worker or two, a cron job, a PostgreSQL instance, and a Key Value store — each metered and billed on its own line, none of them a server you size yourself. Here's the reframe that makes the move straightforward: **a Render app is services, config, and a database** — and your `render.yaml` Blueprint already describes most of it. Your assistant reads that Blueprint the way the [Heroku playbook](/docs/deploy-with-ai/migrate-from-heroku) reads a `Procfile`: every entry under `services` and `databases` is a thing to recreate, and your environment groups are just environment variables. None of it is Render-specific magic — it's a normal Linux deployment that a platform has been managing for you. This recipe hands that translation to your AI assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, your assistant reads your `render.yaml`, turns each service into a `systemd` service on a VM you own, installs the runtime your code needs, migrates your PostgreSQL data with `pg_dump` / `pg_restore`, points your domain at the new server, and turns on HTTPS — all from prompts you paste in. The stack that spread across several Render services usually fits on **one VM** you can resize as you grow. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But migrating an app also means running commands *on* the server — SSH in, install the runtime, restore a database dump, wire up nginx. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so one session can provision the VM, read your local repo and `render.yaml`, and deploy to the box without switching tools. That's the setup this recipe assumes. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when the assistant tells you to. Provisioning and migrating are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only while you take inventory and plan, then switch the key when you're ready to build. ## How a Render app maps to a VM Every piece of a Render Blueprint has a direct equivalent on a server. Your assistant works from this mapping: | On Render | On your American Cloud VM | |---|---| | Web service (`type: web`) | A `systemd` service, with nginx in front as a reverse proxy | | Background worker (`type: worker`) | A `systemd` service that restarts on crash and on boot | | Cron job (`type: cron`) | A `cron` entry on the VM | | Render PostgreSQL (`databases:`) | PostgreSQL installed on the VM, migrated with `pg_dump` / `pg_restore` | | Key Value / Redis | Redis installed on the same VM, listening on localhost | | Static site (`type: web`, `staticPublishPath`) | nginx serving the built output directly from the VM | | Environment groups / env vars | One environment file on the server that every service reads | | Persistent disk (`disk:`) | The VM's own disk, or attached block storage for larger volumes | | Custom domain + managed TLS | DNS records via the [hosted DNS](/docs/dns/dns-management) tools plus a Let's Encrypt certificate from certbot | | Docker-based service (`runtime: docker`) | Docker on the VM — see the [Docker Compose recipe](/docs/deploy-with-ai/docker-compose) | The shape that fits this best is a typical app — Node, Python, Ruby, or Go — with a web service, a worker or two, a PostgreSQL database, and maybe a Key Value store. That's exactly the workload per-service pricing adds up on, and exactly what one VM handles comfortably. ## Before you start - Your app in a local git repo, ideally with its `render.yaml` Blueprint at the root. - Access to your Render dashboard so you can read your environment variable names, find your PostgreSQL connection details, and suspend services when it's time to cut over. - A domain you control, with the ability to point its DNS at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## Phase 1 — inventory your app (read-only) Before anything is created or billed, have your assistant build a complete picture of what it's migrating. This phase is read-only on both sides — it reads your repo and lists American Cloud options without touching your Render services or your account. Open your project in Claude Code and paste: ```text This is a Render app I want to migrate to a server I own. Take inventory first — don't create anything yet: 1. Read render.yaml and list every entry under "services" and "databases": the name, the type (web, worker, cron, static), and the start/build command each one runs. Note any cron schedules. 2. Detect the runtime and version: check for package.json / requirements.txt / pyproject.toml / Gemfile / go.mod and tell me the language and version the app expects, plus any system packages it implies (image libs, a build step, a native module, etc.). Note whether any service uses runtime: docker. 3. List the NAMES of the environment variables the app reads (from the envVars blocks in render.yaml and by grepping the code for env lookups). Do NOT ask me for their values — I'll set those on the server myself. 4. Tell me which backing services this app needs: PostgreSQL? a Key Value / Redis store? a persistent disk? anything else? Then summarize it back to me as a migration target: how many services I'll run, what runtime to install, and what to install for the database and cache. ``` ### What your assistant will do This phase is your assistant reading files — your local repo and, through the MCP server, your American Cloud options: 1. **Read the `render.yaml` Blueprint.** Each entry under `services` becomes one service to recreate. A `type: web` service is the public app; `type: worker` is a background process; `type: cron` is a scheduled command; `type: web` with a `staticPublishPath` is a static site. The `databases:` block tells it you need PostgreSQL. 2. **Identify the runtime from the manifest.** A `package.json` means Node; `requirements.txt` or `pyproject.toml` means Python; a `Gemfile` means Ruby; `go.mod` means Go. This is what Render inferred from your service settings — your assistant installs that exact runtime on the VM instead. If a service declares `runtime: docker`, it's a container build, and the [Docker Compose recipe](/docs/deploy-with-ai/docker-compose) is the better fit for that part. 3. **Collect env var *names*.** It reads the `envVars` blocks in `render.yaml` and greps your code for environment lookups (`process.env.*`, `os.environ[...]`, `ENV[...]`) so the server's environment file has every key the app reads — without ever needing the secret values. 4. **Map the backing services.** A `databases:` block means PostgreSQL on the VM; a Key Value store means Redis; a `disk:` mount means either the VM's own disk or a block storage volume, depending on how much you store. **Never paste secret env values into the chat.** Your assistant only needs the *names* of your environment variables to build the env file's structure. Put the real values — database passwords, API keys, signing secrets — directly into the server's env file over SSH, where they stay on the box you own. Treat them like any other secret: not in the conversation, not in the repo. ## Phase 2 — plan and price (read-only) With the inventory in hand, ask for a sized plan and a cost estimate. This is still read-only — cost estimates create nothing. ```text Based on that inventory, plan the American Cloud side. List the available regions and current Ubuntu images and the VM packages. Recommend ONE VM size that comfortably runs the web service, the worker(s), PostgreSQL, and the Key Value store together, with headroom for my database size. Show me the monthly cost estimate before I approve anything, so I can compare it to my Render bill. ``` **What your assistant will do:** 1. Call `list_regions`, `list_images` (filtered to Ubuntu), and `list_vm_packages` to find a region near you, a current Ubuntu LTS image, and a compute tier whose CPU, memory, and disk fit your workload. 2. Call `get_cost_estimate_vm` with that exact region, package, size, and image, and show you the **hourly and monthly numbers before creating anything**. Nothing is billed yet. 3. Hand you a side-by-side: one VM running everything versus the stack of Render services and managed add-ons on your current bill. You bring the Render numbers; the assistant brings the American Cloud estimate. Because your web service, workers, database, and cache all share one machine, you're sizing one server instead of paying per metered service. Need more later? `scale_vm` resizes it in place. ## Phase 3 — provision and deploy Now the writes begin. This is the build prompt — paste it after you've approved the plan and cost from Phase 2. Read each step's output before approving the next. ```text Go ahead and build the new home for this app. Walk through it step by step and wait for my confirmation on anything that costs money: 1. Check whether I have an SSH key registered; if not, create one and tell me where the private key is saved. 2. Create the Ubuntu VM we sized, on an isolated network, with that SSH key, and open inbound ports 22, 80, and 443. 3. Over SSH, install the runtime from my manifest (the exact language version), plus the system packages the app needs, PostgreSQL, and Redis. Keep both PostgreSQL and Redis listening on localhost only. 4. Clone this repo onto the VM, install dependencies, and run the build. 5. Create the app's environment file from the env var NAMES we found, with placeholder values — I'll fill in the real secrets myself afterward. Point the database URL and the Key Value URL at the local PostgreSQL and Redis. 6. Turn each service from render.yaml into its own systemd service that reads that environment file, restarts on crash, and starts on boot. Put nginx in front of the web service as a reverse proxy on port 80. For any static site, configure nginx to serve its built output directly. 7. Turn any cron services into cron entries on the VM. Don't start the app against real data yet — we'll migrate the database next. ``` **What your assistant will do:** 1. **Sort out the SSH key.** It calls `list_ssh_keys`; if nothing fits, `create_ssh_key` generates a pair — the private key is returned once and never stored, so the assistant saves it locally and sets the right permissions. It needs this key to install on the VM and to SSH in afterward. 2. **Create the server.** On your go-ahead, `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess.inboundPorts` to open 22, 80, and 443 — this opens the firewall *and* the port forwarding together, so those ports are actually reachable from the internet, not just allowed by a rule. It also carries `keypairs` to install your key. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` and it has a public IP. 3. **Install the stack over SSH.** It installs the exact runtime your manifest declares, the system packages your app needs, then PostgreSQL and Redis — both bound to `localhost` so neither is exposed to the internet. Nothing new opens on the firewall for them. 4. **Lay down the environment file.** It writes one env file keyed by every env var name from Phase 1, with placeholders, and points the database and Key Value URLs at the local services. You fill in the real secret values over SSH after this step. 5. **Recreate the services.** Each `render.yaml` service becomes a `systemd` unit reading that env file — web and workers each get one, restarting on crash and on boot. nginx reverse-proxies the public ports to the web service. A static site is different: there's no long-running process, so nginx serves the built files (the `staticPublishPath` output) directly. 6. **Schedule the jobs.** Each `type: cron` service becomes a `cron` entry on the VM with the same schedule and command. Opening a port later, after the VM exists, takes **both** a firewall rule and a port forwarding rule — a firewall rule alone does not make a port reachable. If you ask the assistant to expose a new port down the road, it'll call `create_firewall_rule` *and* `create_port_forwarding_rule` (or `enable_static_nat`). Opening 22, 80, and 443 up front via `create_vm`'s `inboundPorts` handles both at once. ## Phase 4 — migrate the data This is the only phase with real downtime, so it's deliberately last and deliberately careful. The goal is a clean cutover: freeze writes on Render, take a final dump, restore it on the VM, and verify nothing was lost. ```text Now migrate the database with minimal downtime: 1. I'll suspend the web and worker services on Render (or put the app in maintenance mode) so nothing writes to the database while we copy it — tell me when to do that. 2. Take a final pg_dump of the Render PostgreSQL database in custom format, using its external connection string. 3. Copy the dump to the VM and pg_restore it into the local PostgreSQL. 4. Run the app's migration command against the restored database. 5. Verify the migration: compare row counts on the main tables between the Render database and the restored one, and flag any mismatch. 6. Start the systemd services and confirm the app responds locally on the VM (curl the health endpoint through nginx). Report the row-count comparison and the local health check before we touch DNS. ``` **What your assistant will do:** 1. **Freeze writes.** You suspend the Render services (or enable maintenance mode) so the live app stops writing mid-copy — the dump is then a consistent point-in-time snapshot. 2. **Take the final dump.** A `pg_dump` in custom format against your Render PostgreSQL external connection string captures schema and data. 3. **Restore on the VM.** It copies the dump over and runs `pg_restore` into the local PostgreSQL you installed in Phase 3. 4. **Run migrations.** Your app's migration command runs against the restored database so the schema matches the code being deployed. 5. **Verify counts.** It compares row counts on your key tables between source and target and surfaces any difference — your proof the data arrived intact before you commit to the cutover. 6. **Smoke-test locally.** It starts the services and curls the app through nginx *on the VM itself*, confirming the stack works end to end before any public traffic hits it. Your Key Value store is usually a cache or a job queue, not a system of record, so it rarely needs a data copy — a fresh Redis is fine, and the worker repopulates it. If yours holds data you can't lose, tell the assistant and it'll dump and restore Redis the same way. ## Phase 5 — DNS cutover and HTTPS With the app verified on the VM, point your domain at it and switch on TLS. ```text Cut my domain {your-domain.com} over to the new VM: 1. Check whether the domain is already a hosted DNS zone here; if not, create it and tell me the nameservers to set at my registrar. 2. Lower the TTL first if it's high, then point the A record at the VM's public IP. 3. Once DNS resolves to the VM, provision a Let's Encrypt certificate with certbot and switch nginx to HTTPS with auto-renewal. Keep the Render services suspended — anyone still on cached DNS should not be able to write to the old database. Tell me when https://{your-domain.com} is live and served from the new server. ``` **What your assistant will do:** 1. Call `list_dns_zones`; if your domain isn't hosted here, `create_dns_zone` adds it and the assistant shows you the American Cloud nameservers to set at your registrar. A nameserver change has its own propagation window, separate from any record's TTL. 2. Call `create_dns_record` to add (or update) the `A` record pointing your domain at the VM's public IP. New records get a short TTL so future changes cut over fast. 3. Once DNS resolves to the VM, run certbot for a Let's Encrypt certificate, reconfigure nginx for port 443, and enable automatic renewal. **Keep the Render services suspended from the final dump until you decommission.** While DNS propagates, some visitors still resolve to Render — with the services suspended, they can't read or write the *old* database. Bringing them back during propagation is how migrations lose data. A few notes on timing. Lowering the TTL only takes effect at whichever DNS host currently serves your domain, and only after the *old* TTL has expired — so lower it well before cutover day. If you're moving the domain's nameservers to American Cloud, that move propagates on its own schedule on top of any record TTL. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* certbot also needs DNS to resolve to the VM before it can issue the certificate. ## Phase 6 — verify, then decommission Run on the new server for a day or two before you delete anything on Render. Keep the Render services around (suspended) — they're your rollback if something surfaces under real traffic. ```text The app's been live on the VM for a couple of days and looks healthy. Walk me through decommissioning Render safely: confirm the VM is the only thing serving the domain, remind me to take one final offline backup of the database, and list the steps to delete the Render services, the PostgreSQL instance, and the Key Value store once I'm sure. ``` The assistant can confirm the American Cloud side — the VM is `STARTED`, the services are running, the certificate is valid — but the actual Render teardown stays in your hands: take one last database backup to keep offline, then delete the services, the PostgreSQL instance, and the Key Value store when you're confident. From here, every future deploy is a push-and-restart on a server you own. ## Follow-up: a one-prompt deploy command The migration is the hard part. Make every future deploy trivial: ```text Set up a deploy script in this repo that ships updates to the VM: push the latest committed code over SSH, install dependencies, run the build and the migration command, and restart the web and worker systemd services. Add a "deploy" entry to my package.json (or a task runner) and document the one command I run from now on. ``` After this, shipping a change is *"run the deploy script"* — or just *"deploy the latest"* and the assistant runs it. ## Troubleshooting **A service won't start after migration.** Ask your assistant to *"show me the journalctl logs for the web (or worker) service and tell me what's failing."* The usual culprit is a missing or placeholder value in the environment file — confirm every env var name from Phase 1 has its real value set on the server, not a placeholder. **The app can't reach the database.** Have the assistant confirm PostgreSQL is running and that the database URL in the env file points at `localhost` with the right database and user. Since PostgreSQL listens only on `localhost`, nothing on the firewall needs to change — connections stay on the box. **The site is unreachable on 80 or 443.** A reachable port needs both a firewall rule and a forwarding path. Ask your assistant to *"list the firewall and port forwarding rules on the VM's public IP and confirm 80 and 443 are open end to end."* It can call `list_firewall_rules` and `list_port_forwarding_rules`, then add anything missing with `create_firewall_rule` plus `create_port_forwarding_rule` (or `enable_static_nat`). Have it also check the VM is `STARTED` with `get_vm` and that nginx and the web service are both running. **A static site shows nginx's default page.** Confirm nginx is pointed at the built output directory (the equivalent of Render's `staticPublishPath`) and that the build actually ran on the VM. Ask the assistant to *"show me the nginx site config and the contents of the publish directory."* **SSH connection refused.** Confirm port 22 is open (same firewall and port forwarding check) and that the private key from the `create_ssh_key` step is the one your assistant is using. If the key was lost, the assistant can reset access with `reset_vm_password` or open a browser console session with `create_vm_console`. **Row counts don't match in Phase 4.** Don't cut DNS over. Ask the assistant to re-run the dump and restore — the most common cause is a write that slipped in before the services were suspended. Re-freezing and re-dumping gives a clean snapshot. ## Next steps - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — the same VM-plus-systemd pattern, start to finish - [Run a Docker Compose stack](/docs/deploy-with-ai/docker-compose) — for any service that was building from a Dockerfile on Render - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — move user uploads and backups off the VM filesystem and store them durably - [Back up your VM and data](/docs/deploy-with-ai/backups) — automate the offline snapshots that protect a self-managed server - [Teach your AI agent to deploy here](/docs/deploy-with-ai/agents-md) — add one file to your repo and your agent knows this whole playbook - [Migrate from Heroku](/docs/deploy-with-ai/migrate-from-heroku) — the sibling playbook, if you also have a Heroku app to move ## Migrate from Fly.io Fly.io is good at one thing that makes this migration unusually clean: it runs your app as containers. Your `fly.toml` and your `Dockerfile` already describe almost the entire deployment — the image, the ports it serves, the volumes it mounts, the processes it runs. That's not Fly-specific magic you have to reverse-engineer. It's a container spec, and a container spec runs anywhere Docker does. So the reframe here is simpler than most migrations: **your Fly app is already a container — you're just choosing where it lands.** Your AI assistant reads your `fly.toml` and `Dockerfile`, sizes a server from your Machine specs, and brings the same container up on a VM you own with Docker. For a genuinely multi-service app, the same containers can land on managed Kubernetes instead. This recipe hands that translation to your assistant. With the [American Cloud MCP server](/docs/mcp/overview) connected, it reads your Fly config, provisions a VM, runs your container on it, migrates your volume contents and your Postgres data, points your domain at the new server, and turns on HTTPS — all from prompts you paste in. The single-region VM that results is usually simpler and cheaper than a fleet of metered Machines. ## Why Claude Code for this Any [MCP client](/docs/mcp/overview) can create the infrastructure. But migrating a Fly app also means running commands *on* the server — SSH in, install Docker, run your container, restore a database dump. [Claude Code](/docs/mcp/claude-code) combines the American Cloud tools with your terminal, so one session can provision the VM, read your local repo and `fly.toml`, and deploy to the server without switching tools. That's the setup this recipe assumes. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH and `flyctl` steps yourself when the assistant tells you to. Provisioning and migrating are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety details. Start read-only while you take inventory and plan, then switch the key when you're ready to build. ## How a Fly app maps to a VM Because Fly already runs containers, most of the mapping is one-to-one. Your assistant works from this: | On Fly.io | On your American Cloud VM | |---|---| | Fly Machine (your running container) | The same container, on a VM with Docker — see the [Docker Compose recipe](/docs/deploy-with-ai/docker-compose) | | `fly.toml` `[[services]]` / port config | nginx as a reverse proxy plus Docker port mappings | | Fly volume | A [block storage](/docs/deploy-with-ai/backups) volume mounted on the VM (or the VM's own disk for smaller data) | | Fly Postgres | PostgreSQL installed on the VM, migrated with `pg_dump` / `pg_restore` | | `fly secrets` | A server-side environment file the container reads (variable *names* only in chat) | | Fly certificates + custom domains | DNS records via the [hosted DNS](/docs/dns/dns-management) tools plus a Let's Encrypt certificate from certbot | | Multi-region / anycast IPs | One region you choose, near your users — scaled with a [load balancer](/docs/deploy-with-ai/load-balancer) when you need more than one VM | | `fly deploy` | A redeploy prompt or a deploy script you run from the repo | For most apps this is a near-mechanical translation: the same image, the same env vars, the same exposed port — now on a machine you size once and own outright, instead of a per-Machine bill. ### The one shape that changes: edge and anycast Fly's signature feature is its edge model — your app runs in multiple regions behind an anycast IP, and requests land at the nearest Machine. On a VM, that becomes a conventional single-region deployment: you pick one region close to your users, and traffic goes there. For the large majority of apps — serving one country, one continent, or a team — that's a feature, not a loss. One region you chose means predictable latency, predictable behavior, and no per-Machine bill multiplying across edges. You can still scale horizontally when you need to: put a [load balancer](/docs/deploy-with-ai/load-balancer) in front of several VMs in the same region. If global low-latency is genuinely load-bearing for your app — you measured it, users on other continents feel it — then plan that deliberately with your assistant: pick the regions that matter and stand up a VM in each. Just make it a decision, not a default you inherited from the platform. ## When to use Kubernetes instead If your Fly app is really one container with a database behind it, a single VM is the right home — keep reading. But if `fly.toml` defines several processes that scale independently, or you're already running multiple Machine groups that talk to each other, that's a multi-service app, and [managed Kubernetes](/docs/deploy-with-ai/kubernetes) is the better landing zone. Your assistant can build the same container images into a Kubernetes deployment instead of a VM. The inventory phase below tells you which case you're in. ## Before you start - Your app in a local git repo, with its `fly.toml` and `Dockerfile`. - `flyctl` installed and logged in, so the assistant (or you) can read volume and secret metadata and run the final database dump. The names of your Fly secrets are enough — you don't need to expose their values. - A domain you control, with the ability to point its DNS or nameservers at American Cloud. - The MCP server connected to your assistant with a read-write key and `--allow-writes`. ## Phase 1 — inventory your app (read-only) Before anything is created or billed, have your assistant build a full picture of what it's migrating. This phase is read-only on both sides — it reads your repo and lists American Cloud options without touching your Fly app or your account. Open your project in Claude Code and paste: ```text This is a Fly.io app I want to migrate to a server I own. Take inventory first — don't create anything yet: 1. Read fly.toml and the Dockerfile. Tell me: the image being built, the internal port the app listens on, every [[services]] / port mapping, the [processes] section if there is one, and any [mounts] (Fly volumes) with their mount paths. 2. Tell me whether this is a single-service app or a multi-service one — does it run more than one process group that scales independently? 3. If flyctl is available, list my Fly volumes (and sizes) and the NAMES of my Fly secrets. Do NOT print secret values — only the names. Tell me whether a Postgres app is attached. 4. Note which region(s) this app currently runs in and whether it uses more than one. Then summarize it as a migration target: single VM or Kubernetes, what to run the container on, what data to move, and which secret names I'll need to set on the server. ``` ### What your assistant will do This phase is your assistant reading files — your local repo, your Fly metadata via `flyctl`, and your American Cloud options through the MCP server: 1. **Read `fly.toml` and the `Dockerfile`.** Together they define the deployment: the image, the internal port (`internal_port` under `[[services]]` or the modern `[http_service]`), the public port mapping, the process groups, and the volume mounts. This is the spec the assistant recreates. 2. **Decide single VM vs. Kubernetes.** One process group serving web traffic with a database behind it is a single-VM app. Several independently scaled process groups is a multi-service app that belongs on [Kubernetes](/docs/deploy-with-ai/kubernetes). 3. **List volumes and secret names.** `flyctl volumes list` shows what persistent data exists and how big it is — that sizes the block storage you'll attach. `flyctl secrets list` shows the *names* of your secrets (Fly never reveals the values), giving the assistant the keys for the server-side env file without ever seeing the secrets themselves. 4. **Check for attached Postgres.** Fly Postgres runs as its own app; if one is attached, it's a database to dump and restore, and the env file gains a `DATABASE_URL`. 5. **Note the region footprint.** One region is a straight move. Multiple regions is the cue to have the deliberate single-region-vs-multi-VM conversation from above before building. **Never paste secret values into the chat.** Your assistant only needs the *names* of your Fly secrets to build the env file's structure. Put the real values — database passwords, API keys, signing secrets — directly into the server's env file over SSH, where they stay on the box you own. Not in the conversation, not in the repo. ## Phase 2 — plan and price (read-only) With the inventory in hand, ask for a sized plan and a cost estimate. This is still read-only — cost estimates create nothing. ```text Based on that inventory, plan the American Cloud side. List the available regions and pick one near where my users are. List the current Ubuntu images and the VM packages. Recommend ONE VM size that comfortably runs my container plus PostgreSQL, with headroom for my volume and database sizes. Show me the monthly cost estimate before I approve anything, so I can compare it to my Fly bill. ``` **What your assistant will do:** 1. Call `list_regions` and pick one close to your users (replacing Fly's multi-region edge with a single deliberate region), then `list_images` (filtered to Ubuntu) for a current LTS image and `list_vm_packages` for a compute tier. It sizes from your Fly Machine specs — Machines are deliberately small and metered, so add headroom for running the container and the database on one box. 2. Call `get_cost_estimate_vm` with that exact region, package, size, and image, and show you the **hourly and monthly numbers before creating anything**. If you're attaching a block storage volume for your data, it can also call `get_cost_estimate_block_storage`. Nothing is billed yet. 3. Hand you a side-by-side: one owned VM versus your current Fly Machines, volumes, and Postgres app. You bring your Fly bill; the assistant brings the American Cloud estimate. Because one VM runs the container and the database together, you size a single server you can grow later with `scale_vm`, instead of paying per Machine across regions. ## Phase 3 — provision and deploy Now the writes begin. This follows the same VM-with-Docker flow as the [Docker Compose recipe](/docs/deploy-with-ai/docker-compose) — paste this after you've approved the plan and cost from Phase 2, and read each step's output before approving the next. ```text Go ahead and build the new home for this app. Walk through it step by step and wait for my confirmation on anything that costs money: 1. Check whether I have an SSH key registered; if not, create one and tell me where the private key is saved. 2. Create the Ubuntu VM we sized, on an isolated network, with that SSH key, and open inbound ports 22, 80, and 443. 3. If my app has a Fly volume, create a block storage volume of the right size, attach it to the VM, and mount it at the same path the container expects. 4. Over SSH, install Docker Engine and the compose plugin. Build my Dockerfile (or pull my image) on the VM. 5. Create the app's environment file from the Fly secret NAMES we found, with placeholder values — I'll fill in the real secrets myself afterward. If Postgres is attached, install PostgreSQL on the VM, keep it on localhost, and point DATABASE_URL at it. 6. Run the container with the same port mapping and volume mount fly.toml declares. Put nginx in front of it as a reverse proxy on port 80. Don't start the app against real data yet — we'll migrate the volume and the database next. ``` **What your assistant will do:** 1. **Sort out the SSH key.** It calls `list_ssh_keys`; if nothing fits, `create_ssh_key` generates a pair — the private key is returned once and never stored, so the assistant saves it locally and sets the right permissions. It needs this key to install on the VM and to SSH in afterward. 2. **Create the server.** On your go-ahead, `create_vm` provisions the Ubuntu VM. The same call carries `networkAccess.inboundPorts` to open 22, 80, and 443, and `keypairs` to install your key. Opening ports through `create_vm` sets up the firewall rule *and* the port forwarding together, so the ports are actually reachable — a firewall rule on its own would not be. The VM provisions asynchronously, so the assistant polls `get_vm` until its status reaches `STARTED` with a public IP. 3. **Attach storage for your volume.** If your `fly.toml` declares a `[mounts]` volume, the assistant calls `create_block_storage_volume` sized to match, `attach_block_storage_volume` to connect it to the VM, then formats and mounts it at the path your container expects. Smaller data can simply live on the VM's own disk instead. 4. **Install Docker and build the image.** Over SSH it installs Docker Engine and the compose plugin, then builds your `Dockerfile` on the VM (or pulls the image you already publish). This is the same container Fly was running. 5. **Lay down the environment file and database.** It writes one env file keyed by every Fly secret name from Phase 1, with placeholders you fill in over SSH. If Postgres is attached, it installs PostgreSQL bound to `localhost` so it's never exposed to the internet, and sets `DATABASE_URL` to point at it. 6. **Run the container.** It starts your container with the same published port and volume mount your `fly.toml` declares, and puts nginx in front as a reverse proxy on port 80. Tell the assistant to **explain each step before it runs it** if you want to follow along — *"narrate what you're about to do and why."* Destructive operations are flagged regardless, and clients that support confirmations prompt you before anything irreversible. ## Phase 4 — migrate the data This is the only phase with real downtime, so it's deliberately last and deliberately careful. There are two kinds of data to move: the contents of your Fly volume, and your Postgres database. The goal is a clean cutover — freeze writes on Fly, copy everything, restore on the VM, and verify nothing was lost. ```text Now migrate the data with minimal downtime: 1. If there's a Fly volume, rsync its contents from the Fly Machine to the mounted block storage volume on the new VM. 2. For the database, stop the Fly app from serving so nothing writes during the copy: scale the Machines to zero (or suspend the app). 3. Take a final pg_dump of the Fly Postgres database in custom format. 4. Copy the dump to the VM and pg_restore it into the local PostgreSQL. 5. Run any database migration command my app needs against the restored data. 6. Verify the migration: compare row counts on the main tables between the Fly database and the restored one, and flag any mismatch. 7. Start the container and confirm the app responds locally on the VM (curl the health endpoint through nginx). Report the row-count comparison and the local health check before we touch DNS. ``` **What your assistant will do:** 1. **Copy the volume contents.** It `rsync`s the files from your Fly volume to the block storage volume mounted on the VM, so uploaded content and any on-disk state come across intact. 2. **Stop the Fly app from serving.** Scaling the Machines to zero (or suspending the app) freezes writes so the database dump is a consistent point-in-time snapshot. Fly Postgres is unmanaged — it's a database you run, not a managed service — so a `pg_dump` / `pg_restore` is exactly the right tool. 3. **Take the final dump.** A `pg_dump` in custom format captures schema and data. 4. **Restore on the VM.** It copies the dump over and runs `pg_restore` into the local PostgreSQL from Phase 3. 5. **Run migrations.** Your app's migration command runs against the restored database so the schema matches the code being deployed. 6. **Verify counts.** It compares row counts on your key tables between source and target and surfaces any difference — your proof the data arrived intact before you commit to the cutover. 7. **Smoke-test locally.** It starts the container and curls the app through nginx *on the VM itself*, confirming the stack works end to end before any public traffic hits it. **Once you take that final dump, the Fly app stays scaled to zero (or suspended) until you decommission it.** Bringing it back up during DNS propagation means it serves the *old* database again — and any writes that land there are lost when you tear it down. Never serve from the old database during the cutover. ## Phase 5 — DNS cutover and HTTPS With the app verified on the VM, point your domain at it and switch on TLS. ```text Cut my domain {your-domain.com} over to the new VM: 1. Check whether the domain is already a hosted DNS zone here; if not, create it and tell me the nameservers to set at my registrar. 2. Lower the TTL first at whatever DNS host currently serves the domain, then point the A record at the VM's public IP with a short TTL. 3. Once DNS resolves to the VM, provision a Let's Encrypt certificate with certbot and switch nginx to HTTPS with auto-renewal. Keep the Fly app scaled to zero — anyone still on cached DNS should fail over, not write to the old database. Tell me when https://{your-domain.com} is live and served from the new server. ``` **What your assistant will do:** 1. Call `list_dns_zones`; if your domain isn't hosted here, `create_dns_zone` adds it and the assistant shows you the American Cloud nameservers to set at your registrar. A nameserver move has its own propagation window, separate from any record TTL. 2. Call `create_dns_record` (or `update_dns_record`) to point the `A` record at the VM's public IP. Lower the TTL *first*, at whichever DNS host currently serves the domain, so caches expire quickly — then give the new record a short TTL so you can react fast if anything's off. 3. Once DNS resolves to the VM, run certbot for a Let's Encrypt certificate, reconfigure nginx for port 443, and enable automatic renewal. This replaces the certificate Fly was managing for your custom domain. **The Fly app stays scaled to zero from the final dump until you decommission it.** While DNS propagates, some visitors still resolve to Fly's anycast IP — with the Machines at zero they fail over rather than silently reading and writing the *old* database. Bringing it back during propagation is how migrations lose data. DNS changes take time to propagate — from a few minutes to a couple of hours, depending on your registrar and the record's TTL. Ask your assistant to *"check what \{your-domain.com\} currently resolves to and tell me when it points at the VM's IP."* certbot also needs DNS to resolve to the VM before it can issue the certificate. ## Phase 6 — verify, then decommission Run on the new server for a day or two before you delete anything on Fly. Keep the Fly app around (scaled to zero) — it's your rollback if something surfaces under real traffic. ```text The app's been live on the VM for a couple of days and looks healthy. Walk me through decommissioning Fly safely: confirm the VM is the only thing serving the domain, remind me to keep a final database dump and volume copy offline, and give me the flyctl commands to destroy the Machines, the Postgres app, and release the Fly IPs once I'm sure. ``` The assistant can confirm the American Cloud side — the VM is `STARTED`, the container is running, the certificate is valid — but the Fly teardown stays in your hands: keep one last database dump and volume copy offline, then run `flyctl` yourself to destroy the Machines, destroy the attached Postgres app, and release the Fly IPs when you're confident. From here, every future deploy is a build-and-restart on a server you own. ## Follow-up: replace `fly deploy` `fly deploy` was your one command to ship. Recreate that ergonomics on the VM: ```text Set up a deploy script in this repo that replaces "fly deploy": push the latest committed code over SSH, rebuild the Docker image on the VM, run my database migration command, and restart the container. Document the one command I run from now on. ``` After this, shipping a change is *"run the deploy script"* — or just *"deploy the latest"* and the assistant runs it. ## Troubleshooting **The container won't start after migration.** Ask your assistant to *"show me the container logs on the VM and tell me what's failing."* The usual culprit is a missing or placeholder value in the environment file — confirm every Fly secret name from Phase 1 has its real value set on the server. **The app can't reach the database.** Have the assistant confirm PostgreSQL is running and that `DATABASE_URL` in the env file points at `localhost` with the right database and user. Since Postgres listens only on `localhost`, nothing on the firewall needs to change — connections stay on the box. **The site is unreachable on 80 or 443.** Ask your assistant to *"list the firewall rules on the VM's public IP and confirm 80 and 443 are open."* A port needs *both* a firewall rule (`create_firewall_rule`) and forwarding (`create_port_forwarding_rule`), or static NAT (`enable_static_nat`), to be reachable — `list_firewall_rules` and `list_port_forwarding_rules` show what's actually in place. Have it also confirm the VM is `STARTED` with `get_vm` and that nginx and the container are both running. **The mounted volume is empty or read-only.** Ask the assistant to *"confirm the block storage volume is attached, formatted, and mounted at the path the container expects, and that the container's volume mount points at it."* A Fly `[mounts]` path that doesn't match the VM mount point is the common cause. **Row counts don't match in Phase 4.** Don't cut DNS over. Ask the assistant to re-run the dump and restore — the most common cause is a write that slipped in before the Machines were scaled to zero. Re-freezing and re-dumping gives a clean snapshot. **Latency feels worse for some users.** That's the edge-to-single-region change showing up. If it's real and load-bearing, ask your assistant to *"plan a second VM in a region closer to those users, behind a load balancer"* — see [scaling with a load balancer](/docs/deploy-with-ai/load-balancer). For most apps the single region is fine; measure before adding machines. ## Next steps - [Deploy a Docker Compose app](/docs/deploy-with-ai/docker-compose) — the VM-with-Docker landing zone this recipe builds on, in full - [Run on Kubernetes](/docs/deploy-with-ai/kubernetes) — the right home for a genuinely multi-service Fly app - [Scale out with a load balancer](/docs/deploy-with-ai/load-balancer) — put several VMs behind one IP when one region needs more than one machine - [Backups with your AI assistant](/docs/deploy-with-ai/backups) — snapshots and offsite dumps for your volume and database - [Teach your AI agent to deploy here](/docs/deploy-with-ai/agents-md) — add one file to your repo and your agent knows this whole playbook ## Migrate from Netlify Netlify is a fast way to get a static site or a Jamstack front end online. But the moment your traffic grows — bandwidth that creeps past the plan, build minutes you keep topping up, a function that's busier than the free tier expects — the bill starts climbing in ways that are hard to predict, and the platform owns more of your stack than you'd like. This recipe moves your site to a server you own on American Cloud, where the cost is a flat monthly rate and the whole runtime is yours. You don't have to learn the Linux part. With the [American Cloud MCP server](/docs/mcp/overview) connected to your AI assistant, the assistant reads your repo, maps each Netlify feature to its place on the new server, prices the move so you can compare it against your real Netlify bill, provisions a small VM, builds and deploys the site, and walks you through a DNS cutover that keeps Netlify serving traffic until you're confident. Your Netlify site's build output is a folder of static files. On the new server, **nginx serves that folder** — that's the landing zone, and it fits comfortably on the smallest VM tier. Object storage isn't where the site lives; it's an optional companion for large media or user uploads the site references. This playbook is a sibling of [Migrate from Vercel](/docs/deploy-with-ai/migrate-from-vercel) — same shape (inventory, plan, provision, map features, cut over), different platform. The underlying provision-and-deploy mechanics come from [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs); read that if you want the details of how a VM, nginx, and HTTPS get set up. Provisioning and DNS changes are write operations. You'll need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag on the MCP server. See the [overview](/docs/mcp/overview) for setup and safety. The inventory phase below is fully read-only — do all of it with a read-only key before you commit to anything. ## What this looks like The migration runs as a guided conversation in six phases. Phases 1 and 2 are read-only — your assistant inspects and plans, nothing is created or billed. Phases 3 through 6 do the move. 1. **Inventory** — the assistant reads your repo and Netlify config and produces a migration map. 2. **Plan and price** — it proposes the smallest VM and a cost estimate to set against your Netlify bill. 3. **Provision and deploy** — it builds the server, builds the site, and points nginx at the output. 4. **Map the features** — redirects, headers, functions, forms, and env vars each get a home. 5. **Cut over** — DNS zone move (if needed) ahead of time, lower TTLs, verify against the new server, switch. 6. **Decommission** — once the new server has proven itself, retire the Netlify site. Do it in a [Claude Code](/docs/mcp/claude-code) session: that client combines the American Cloud tools with your terminal, so one conversation can read the repo, provision the VM, and run the build and config steps over SSH. Cursor and the [other clients](/docs/mcp/other-clients) work too — you'll just run the SSH steps yourself when prompted. ## Phase 1: inventory your site (read-only) Before moving anything, get an honest picture of what Netlify does for you. Some of it is your app (the build command, the publish directory); some of it is Netlify platform behavior — `_redirects`, `_headers`, `netlify.toml`, functions, forms, environment variables, and possibly your DNS — that needs an explicit home on the new server. Open your project and paste this. ```text I'm planning to migrate this site off Netlify to a small VM I own on American Cloud. Don't change or create anything yet — this is a read-only inventory pass. Read the repo and build me a migration map: 1. Read netlify.toml if it exists. List the build command, the publish directory, the functions directory, and every [[redirects]], [[headers]], and [[plugins]] block. 2. Read any _redirects and _headers files. Translate each rule into plain language so I can confirm intent (path, status code, destination, header). 3. List the Netlify Functions (the functions directory) and any scheduled functions. For each, note what it does and what it talks to. 4. Note whether the site uses Netlify Forms (a form with a netlify or data-netlify attribute) and where submissions are expected to go. 5. Read package.json: Node version, build script, and whether the build is memory-hungry. Confirm the build output is a folder of static files. 6. Make a checklist of the environment variables this site reads at build time and at runtime (scan for process.env.* and any framework env usage). List the NAMES only — do NOT ask me to paste secret values into the chat. 7. Tell me whether my domain's DNS is currently served by Netlify (Netlify DNS / Netlify nameservers) or by another registrar/provider. This decides how the cutover works. Output a single migration map: what serves as static files as-is, what needs a server-side equivalent (functions, forms), what nginx rules to write (redirects, headers), and what I need to provide (env values, domain list). ``` ### What your assistant will do This phase touches your filesystem only — no MCP write tools, no calls that cost anything. - **Reads your config.** It opens `netlify.toml`, `_redirects`, `_headers`, your functions directory, and `package.json` directly from the repo. - **Translates the rules.** Each `_redirects` line and `_headers` block becomes a plain-language statement of intent, so you can confirm it before it's turned into nginx config. These get *re-implemented*, not copied — Netlify's rule syntax doesn't run on nginx. - **Classifies the dynamic bits.** Netlify Functions and scheduled functions don't have a static home; the map notes that each becomes a route in a small server-side service (or a cron job) on the same VM. Forms get the same treatment. - **Builds the env-var checklist** by scanning for env usage, listing *names* only. You'll put the *values* on the server directly, never in chat. - **Checks who serves your DNS.** This is the single most important line in the map. If your domain is on Netlify DNS, moving the zone to American Cloud is an early step (Phase 5), not an afterthought. The output is a plain-language map you can sanity-check before a single resource exists. ## Phase 2: plan and price (read-only) Now turn the map into a concrete plan with a number attached — *before* creating anything. The MCP server's cost-estimate tools are read-only, so the assistant can price the whole setup and you can lay it next to your Netlify invoice. ```text Based on the migration map, propose an American Cloud setup and price it. Don't create anything yet. - This site's build output is static files served by nginx, so plan the SMALLEST VM tier — there's no application server to run, just nginx serving a folder. Recommend a region near my users and a current Ubuntu LTS image. - If the inventory found Netlify Functions or Forms, note that a small Node service runs on the same VM alongside nginx. It still fits the smallest tier for typical traffic — call it out if you think it doesn't. - If the site references large media or user uploads, plan an object storage unit for those assets (NOT for the site itself) and price it too. - List the regions, images, and VM packages so I can see the options. - Call the cost-estimate tool for the VM and show me hourly and monthly numbers. Add a public IP if one's needed, and object storage if the map calls for it. - Give me a single monthly total I can compare against my Netlify bill. ``` ### What your assistant will do - **Sizes for static hosting.** Because nginx is just serving a folder, the assistant calls `list_regions`, `list_images` filtered to Ubuntu, and `list_vm_packages`, then recommends the smallest compute tier. A static site has very little to run. - **Accounts for functions and forms.** If the map includes a server-side service (for translated functions or a form endpoint), that's still a lightweight Node process on the same box — usually no bigger a VM, and the assistant flags it if the traffic profile suggests otherwise. - **Adds object storage only when it belongs.** Large media or uploads the site references can move to an S3-compatible object storage unit, priced with `get_cost_estimate_object_storage`. The site's HTML/CSS/JS still live on the VM. - **Prices it before building.** It calls `get_cost_estimate_vm` with the exact region, package, size, and image (plus `get_cost_estimate_public_ip`, and `get_cost_estimate_object_storage` if relevant) and shows the monthly figure. Nothing is billed until you say go. This is the comparison that matters. American Cloud bills a flat rate for the server you choose — not per GB of bandwidth or per build minute, which are the usual reasons a Netlify bill drifts. Put the assistant's monthly estimate next to your last few Netlify invoices and decide with real numbers. ## Phase 3: provision and deploy With the plan approved, the provision-and-deploy follows the same flow as [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs): create a small Ubuntu VM, open the right inbound ports, install nginx over SSH, and turn on HTTPS with Let's Encrypt. The difference for a static Netlify site is the middle: instead of running an app as a service, the assistant **runs your build and points nginx at the output folder**. A few migration-specific notes: - **Where the build runs.** The assistant can build the site locally and copy the output to the VM, or run the build on the VM itself — whichever the inventory found simpler. The result is the same: a folder of static files in nginx's web root. - **Ports.** `create_vm` carries `networkAccess.inboundPorts` to open 22 (SSH), 80 (HTTP), and 443 (HTTPS) in one step. That argument opens the firewall rule *and* the port forwarding together — both halves of making a port reachable. (A firewall rule on its own does not route traffic to the VM; if you ever open another port later, you need both a `create_firewall_rule` and a `create_port_forwarding_rule`, or `enable_static_nat` on the IP.) - **Hold the DNS switch.** Don't point your live domain at the new server yet. Deploy and test against the VM's IP first, while Netlify keeps serving your real traffic. The full end-to-end prompt in Phase 5 wires this together. ## Phase 4: map the Netlify features Most of a Netlify migration is translating platform features into things that run on your own server. Here's how each one maps, and which MCP tools or server-side steps your assistant uses. | Netlify feature | On American Cloud | How | |---|---|---| | Build & hosting | Static files served by nginx on the smallest VM | The assistant builds locally or on the VM, drops the output in nginx's web root | | `_redirects` / `_headers` / `netlify.toml` rules | nginx config | The assistant translates each redirect and header rule into nginx directives, then verifies them against the live server after deploy | | Netlify Functions | Routes in a small Node service on the same VM | A long-running service handles them — often simpler: no cold starts, no per-invocation pricing | | Scheduled functions | `cron` or `systemd` timers | The assistant writes a timer (or crontab line) per schedule over SSH | | Netlify Forms | A small form endpoint in that same Node service | Submissions land in your own store — your data, your server | | Environment variables | Server environment / `systemd` unit | Written into the service's env file over SSH — names in chat, values on the server only | | Netlify DNS | Hosted DNS zone | `create_dns_zone`, `create_dns_record`; update your registrar's nameservers (see Phase 5) | | Large media / uploads | Object storage | `create_object_storage_unit`, `create_object_storage_bucket`, `get_object_storage_keys` — S3-compatible; see [object storage](/docs/deploy-with-ai/object-storage) | A few of these are worth a closer look. ### Redirects and headers Netlify's `_redirects`, `_headers`, and the `[[redirects]]` / `[[headers]]` blocks in `netlify.toml` are a rule syntax that Netlify's edge applies for you. On your own server, nginx does the same job with its own directives. Your assistant reads each rule, translates it — a `301`/`302` redirect becomes an nginx `return` or `rewrite`; a security or caching header becomes an `add_header`; an SPA fallback (`/* /index.html 200`) becomes a `try_files` directive — and then, after deploy, **walks every rule against the running server to confirm it behaves as it did on Netlify.** That verification pass (Phase 5) is what catches a translation that almost-but-not-quite matches. ### Functions A Netlify Function is a small piece of server-side code invoked per request. On the new server, the assistant collects them into one small Node service that runs alongside nginx as a `systemd` service, with nginx reverse-proxying the function paths (commonly `/.netlify/functions/*` or whatever paths your site calls) to it. In practice this is usually *simpler*: one always-warm process, no cold starts, no per-invocation billing. If a function relied on a Netlify-specific runtime helper, the assistant flags it in Phase 1 so you can swap it for the standard Node equivalent. ### Scheduled functions A scheduled function is just a function on a cron expression. Your assistant recreates each schedule as a `systemd` timer (or a crontab line) on the VM that hits the same route on the same cadence — over SSH, so it survives reboots. ### Forms Netlify Forms captures form submissions for you. On your own server, the assistant adds a tiny form endpoint to the same Node service: the form posts to it, and the endpoint writes each submission somewhere you control — a file, a small local store, or an email/notification of your choosing. The positive part of this trade: your submission data lands in your own store on your own server, not a third party's dashboard. ### Environment variables Build-time and runtime env vars move into the service's environment file (or its `systemd` unit) on the VM. Your assistant lists the *names* it found in Phase 1; you supply the *values* directly on the server, never pasted into chat. ## Continuous deploys On Netlify, a `git push` triggers a build and deploy. On a server you own, you replace that with a one-prompt deploy script — the same pattern as the [deploy-nextjs follow-up](/docs/deploy-with-ai/deploy-nextjs): ask your assistant to write a script that pushes the latest committed code to the VM, rebuilds the site, refreshes the nginx web root (and restarts the function service if you have one). After that, shipping a change is *"run the deploy script"* — or just *"deploy the latest."* ```text Set up a deploy script in this repo I can run to ship updates to the server. It should: push the latest committed code to the VM over SSH, run the build there, replace the files in the nginx web root with the new build output, reload nginx, and restart the function service if there is one. Add a "deploy" entry to package.json scripts and document the one command I run from now on. ``` ### Deploy previews Netlify's deploy previews — a fresh URL per branch — don't have a one-to-one equivalent, and that's an honest difference. The workflow becomes *"deploy from a branch when I ask."* If you want a standing preview environment, your assistant can stand up a **second, cheap VM** for a staging copy of the site on request, deploy a branch to it, and tear it down when you're done — you only pay for it while it's up. ## Phase 5: cut over without downtime This is the part unique to migrating a live site. The goal: bring the new server fully online, prove it works, and only *then* move traffic — with Netlify still up as your safety net. ### If your domain is on Netlify DNS, move the zone first Check the Phase 1 finding. If your domain's DNS is served by **Netlify DNS** (your registrar points at Netlify's nameservers), the zone move is a **required early step**, because the place you change records *is currently Netlify*. Do this ahead of the cutover, not during it: - The assistant creates the zone on American Cloud with `create_dns_zone` and recreates your existing records (`create_dns_record`) — keeping them pointed where they point today, including the record(s) that still send web traffic to Netlify. - You then change your **nameservers at the registrar** to American Cloud's. That nameserver change has its own propagation window (it can take a while, since registrar/TLD nameserver TTLs are long), so doing it early — while records still resolve to Netlify — means no visitor sees a gap. - Once the zone is authoritative on American Cloud, the actual cutover is a single record edit with a short TTL, fully under your control. If your domain is **not** on Netlify DNS (it's at another registrar/provider), you don't have to move the zone at all — you can simply edit the record at your current provider during the cutover. Either way, the TTL rule below applies. ### Lower your DNS TTL ahead of time TTL is how long resolvers cache a record. A high TTL means a cutover takes hours to take effect everywhere — and a rollback would too. **Lower the TTL on the record you'll switch — at whichever host currently serves the domain — a day or two ahead** (60 seconds is fine). If the domain is still on Netlify DNS at this point, that's where you lower it; if you've already moved the zone to American Cloud, new records there get short TTLs automatically and the assistant can confirm. Then, when you flip the record, traffic moves fast and a rollback is just as quick. **Test against the new server before you touch DNS.** Your assistant can hit the VM's public IP directly with the right `Host` header — e.g. `curl -H "Host: your-domain.com" https://VM_IP/ --resolve your-domain.com:443:VM_IP` — so it sees exactly what visitors will see while real DNS still points at Netlify. Or it can add a temporary line to your local `hosts` file mapping your domain to the VM's IP so you can click through the whole site in a browser. Ask: *"verify the migrated site against the VM's IP with my domain's Host header — walk every redirect rule, every form, and every function the inventory found, and show me the results."* Here's the prompt that runs the migration end to end and lands on a careful cutover: ```text Execute the migration to American Cloud using the plan and prices we agreed on. Narrate each step and pause before anything destructive or anything that moves real traffic. 1. Provision the VM: small Ubuntu VM, my SSH key, inbound ports 22/80/443 open (networkAccess.inboundPorts, which opens firewall + forwarding together). Wait until it's STARTED with a public IP. 2. Install nginx. Build the site (locally or on the VM, whichever we decided), and put the output in the nginx web root. 3. Translate every _redirects / _headers / netlify.toml rule into nginx config and load it. 4. If the inventory found Functions/Forms, set up the small Node service as a systemd service, reverse-proxied behind nginx, and recreate any scheduled functions as systemd timers. Put my env-var VALUES in the service's env file directly (I'll give them to you — not in chat). 5. If the site references large media/uploads, set up object storage and point the site at it as we discussed. 6. Provision a Let's Encrypt certificate so the VM serves HTTPS for my domain, even though DNS doesn't point here yet (use the DNS-01 path or a temporary verification as needed). 7. Before any DNS change: verify the site against the VM's IP using my domain's Host header. Walk EVERY redirect rule, every header, every form, and every function from the inventory. Show me the results. 8. When I confirm it's good: make sure the TTL on the record I'm switching is already low, then point the A record for my domain at the VM's public IP. 9. Watch resolution until my domain points at the VM, then confirm the live site loads over HTTPS. Leave my Netlify site running untouched. ``` ### What your assistant will do 1. **Builds and deploys** as in the [deploy recipe](/docs/deploy-with-ai/deploy-nextjs): `create_vm` with `networkAccess.inboundPorts` to open 22/80/443 and `keypairs` for your SSH key, polling `get_vm` until `STARTED`, then nginx and your built site over SSH. 2. **Re-implements your rules.** Translated redirects and headers go into the nginx config; functions become a `systemd`-managed Node service behind nginx; scheduled functions become timers; env values go into the service's env file. 3. **Gets HTTPS ready early** so the new server can serve your domain over TLS before any traffic arrives. 4. **Verifies against the IP.** Using a `Host`-header `curl` or a temporary `hosts` entry, it walks every redirect, header, form, and function the inventory found — all while Netlify still serves your users. 5. **Cuts over deliberately.** Only on your confirmation does it switch the `A` record (`update_dns_record` on an American Cloud zone, or it tells you the change to make at your DNS provider) to the VM's public IP, then watches resolution until your domain points at the new server. 6. **Leaves Netlify running.** Because the TTL is low, rollback is fast: if anything looks wrong, point the record back at Netlify and you're restored in seconds. ## Phase 6: decommission Netlify — when you're sure Give it a day or two. Watch the new server's traffic and error logs, confirm every redirect still behaves, check that forms are landing where they should and any scheduled jobs are firing. When you're confident the new server carries everything Netlify used to, then — and only then — retire the Netlify site. There's no rush: keeping it up a little longer costs little and buys you a clean rollback the whole time. ```text The migrated site has been healthy for a couple of days. Confirm the VM is serving traffic, the redirects and headers all behave, forms are landing in my store, and the scheduled-job timers have run on schedule. Then give me a checklist for safely removing the Netlify site (and, if I moved my domain off Netlify DNS, confirming nothing still depends on it). ``` ## Next steps - [Deploy a Next.js app with your AI assistant](/docs/deploy-with-ai/deploy-nextjs) — the full provision-and-deploy mechanics this playbook builds on - [Migrate from Vercel](/docs/deploy-with-ai/migrate-from-vercel) — the sibling playbook for a Next.js deployment on Vercel - [Object storage with your AI assistant](/docs/deploy-with-ai/object-storage) — a home for large media and uploads your site references - [Backups with your AI assistant](/docs/deploy-with-ai/backups) — snapshots and object-storage backups for your new server - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — capture your deploy conventions so future sessions repeat them ## Migrate WordPress Shared hosting — cPanel, a "unlimited" plan, a control panel you log into twice a year — was the default way to run WordPress for a decade. It's cheap until it isn't: a noisy neighbor on the same box slows your site, backups are something you keep meaning to set up, and "managed" means you're the one managing it. [American Cloud managed WordPress](/docs/wordpress/wordpress-hosting) gives you the other side of that trade — resource isolation, Redis object caching, AccelerateWP, SSL/TLS by default, automated backups, staging and cloning, and proactive monitoring — without you becoming a sysadmin. This recipe moves an existing WordPress site there. Everything comes with it: themes, plugins, media, and the database. Your AI assistant — connected to the [American Cloud MCP server](/docs/mcp/overview) — takes inventory of your current site, helps you stand up the destination, walks you through the documented migration method one step at a time, and handles the DNS cutover so traffic moves cleanly with your old host as a safety net until you're sure. The WordPress tools are **not** in the MCP server's default service set. Start the server with `--services wordpress` (or `--services all`) to expose them — for example `npx @americancloud/mcp --services wordpress,dns`. Creating a site, changing a password, and editing DNS are write operations, so you'll also need a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag. The inventory and pricing steps below are read-only — do all of those with a read-only key first. See the [MCP overview](/docs/mcp/overview) for setup and safety. ## What this looks like The move runs as a guided conversation in five phases. The first two are read-only — your assistant inspects, plans, and prices, and nothing is created or billed. The last three do the actual migration. 1. **Inventory** — take stock of what's on your current site so nothing gets left behind. 2. **Set up the destination** — create the managed WordPress instance and pick the right plan. 3. **Migrate** — move themes, plugins, media, and the database using the [documented migration method](/docs/wordpress/migrations). 4. **Cut over DNS** — point your domain at American Cloud with short TTLs and your old host still live. 5. **Verify and decommission** — confirm everything renders, then cancel the old hosting. Prefer not to touch any of it yourself? American Cloud offers **complimentary WordPress migrations** — our team transfers your site, database, and core configuration with minimal downtime. If that's the route you want, skip straight to [WordPress migrations](/docs/wordpress/migrations) and [contact us](https://americancloud.com/contact-us). The rest of this page is for doing it yourself with your assistant as a guide. ## Phase 1: inventory your current site (read-only) Before moving anything, get an honest picture of what your shared host is actually running. The goal is a checklist you can verify against after the move — so a missing plugin or a broken form shows up on a list, not as a surprise from a visitor. Your assistant can't log into your cPanel account, so this phase is a structured interview plus whatever it can read from the live site. Open a chat and paste this. ```text I'm migrating a WordPress site off shared/cPanel hosting to American Cloud managed WordPress. Don't change anything — help me take inventory first. Build me a migration checklist by asking me for, and recording: 1. The site's current domain(s), and where DNS is managed today (the shared host, a registrar like GoDaddy/Namecheap, or Cloudflare). 2. The active theme and any child theme. 3. The full plugin list, and which plugins are licensed/premium (those may need a license re-activation after the move). 4. Roughly how big the site is: total disk used, database size, and the size of the uploads/media library. (I can read these from cPanel's file manager or the WordPress dashboard.) 5. Anything stateful I might forget: contact-form recipients, transactional or SMTP email settings, scheduled posts, custom .htaccess rules, and the permalink structure. 6. The list of pages and key URLs I'll want to spot-check after the move. Then fetch my public homepage and a couple of inner pages and note what loads, so we have a "before" reference to compare against later. ``` ### What your assistant will do This phase touches nothing you're billed for and changes nothing on either host. - **Interviews you** for the things only you can see — the cPanel disk usage, the premium plugin licenses, the SMTP credentials — and writes them into one checklist. - **Reads the live site** where it can, capturing a "before" picture of the homepage and a few inner pages so you have something concrete to compare against post-migration. - **Flags the easy-to-forget items**: form recipients, scheduled posts, the permalink structure, and any custom `.htaccess` behavior — the parts that look fine until someone fills in a form or hits a deep link. The output is a plain-language inventory you'll check off in Phase 5. ## Phase 2: set up the destination Now create the managed WordPress instance your site will live on. American Cloud managed WordPress includes its own database and the full performance and security stack — caching, SSL, automated backups, staging — so the destination is a complete home, not a bare server you have to assemble. There are two honest paths here, and your assistant can guide either: - **The dashboard** is the documented walkthrough. [WordPress hosting](/docs/wordpress/wordpress-hosting) takes you click by click through choosing a plan, optionally entering a custom domain, reviewing the cost estimate, and creating the instance. If you'd rather see the screens and the cost panel before committing, do it here. - **The MCP server** can do the same provisioning from the conversation. Your assistant can list the available plans, price your choice before anything is billed, and create the instance — then read back its nameservers, quota, and websites. Either way, **the plan menu and pricing are whatever the dashboard and the plans show** — don't take a price from this page. Use the cost-estimate step (the assistant's preview, or the cost panel in the dashboard) for the real number. ```text Help me set up the American Cloud managed WordPress destination. Show me the cost before creating anything. 1. List the available WordPress packages and summarize each one's disk, bandwidth, site count, and visit allowance so I can match it to the inventory from Phase 1. 2. Recommend the smallest package that comfortably fits my site's disk and media size, my expected traffic, and the number of sites I need to host. 3. Show me the cost estimate for that package — monthly and prorated — and wait for me to confirm. 4. Once I confirm, create the managed WordPress site on that package. Then read back its details: status, the temporary site address, the nameservers, and the quota. ``` ### What your assistant will do - **Lists and explains the plans.** It calls `list_wordpress_packages` and lays each tier's disk, bandwidth, site limit, and visit allowance next to your Phase 1 numbers so the choice is grounded in your actual site, not a guess. For agency-scale or custom needs, it can point you to [Enterprise WordPress plans](/docs/wordpress/enterprise-plans). - **Prices before provisioning.** `get_cost_estimate_wordpress` previews the monthly and prorated cost for the package you're leaning toward. Nothing is billed until you say go. - **Creates the instance** with `create_wordpress` on the confirmed package, then reads it back with `get_wordpress`, `get_wordpress_nameservers`, and `get_wordpress_quota` — so you immediately have the temporary `*.wpsquared.site` address to migrate into and the nameservers you'll need in Phase 4. Leave your **custom domain off the new instance for now**, or let it provision on the temporary `*.wpsquared.site` address. You'll do the migration against that temporary address while your real domain still points at the old host — then switch DNS in Phase 4 only after you've verified the migrated site. See [WordPress hosting](/docs/wordpress/wordpress-hosting) for how the temporary domain and custom domain work. ## Phase 3: migrate the site This is where the content moves. American Cloud's [documented self-service migration method](/docs/wordpress/migrations) uses the **All-in-One WP Migration** plugin: you install it on your existing site, generate a full-site export (themes, plugins, media, and the database in one file), and upload that export into your new American Cloud WordPress environment. Once it's imported, the site is verified, caching and performance features are enabled, and SSL is applied. These steps happen **inside WordPress itself**, in the wp-admin of each site — not through MCP tools. That's the honest division of labor: the assistant is your patient guide through the documented method, and the MCP server gets you signed in and confirms the destination is healthy, but the export and import are clicks in the WordPress admin. ```text Walk me through migrating my site using American Cloud's documented method (the All-in-One WP Migration plugin), one step at a time. Wait for me to confirm each step before moving on. Source side (my old shared/cPanel site): 1. Tell me how to install the All-in-One WP Migration plugin from the WordPress plugin directory. 2. Walk me through running a full-site export and downloading the export file. Tell me what should be included. Destination side (my new American Cloud site): 3. Create a one-time admin login session for my American Cloud WordPress site and give me the link, so I can reach wp-admin without hunting for a password. 4. Walk me through installing All-in-One WP Migration on the new site and importing the export file I downloaded. 5. After import, tell me exactly what to check before I touch DNS: that the theme and child theme are active, the plugins are present (I'll re-activate any premium licenses), the media library loaded, and the permalink structure matches. Then read back the new site's quota and website list so I can confirm the database and files arrived at the size I expected. ``` ### What your assistant will do - **Guides the documented method, step by step.** It points you at [WordPress migrations](/docs/wordpress/migrations) and the All-in-One WP Migration plugin — install on the old site, export, import on the new site — and recommends only that method. (For very large media libraries, it'll suggest checking the export size against your new plan's quota first, so the import doesn't bump a limit.) - **Gets you into wp-admin without a password hunt.** `create_wordpress_session` mints a short-lived, one-time URL that opens your American Cloud WordPress dashboard already signed in — handy for the destination side of the import. If you'd rather set a known password, your assistant can use `update_wordpress_password` (or you can update it from the dashboard). - **Confirms the destination is healthy.** After the import, it reads `list_wordpress_websites` and `get_wordpress_quota` so you can see the migrated site listed and check that the database and files landed at roughly the size your inventory predicted — a quick sanity check that the whole site actually came across. You're still safe to abort at this point. Your old site is untouched and still serving your live domain; the new site is reachable only on its temporary address. Nothing public has changed yet. ## Phase 4: cut over DNS With the migrated site verified on its temporary address, point your domain at American Cloud. The principle is the same as any careful cutover: **lower your TTL first, switch second** — so traffic moves fast and a rollback is just as quick. **Lower the TTL where your domain's DNS lives today.** That's whatever host currently serves your domain — often the old shared host itself, or your registrar (GoDaddy, Namecheap), or Cloudflare if you put it in front. Drop the records' TTL to something short (for example 60 seconds) a day or two ahead of the switch. A high TTL means resolvers cache the old answer for hours; a low one means your cutover — and any rollback — takes effect in seconds. Then make the change using the [documented DNS setup](/docs/wordpress/wordpress-hosting). There are two supported ways to do it: - **Point your registrar's nameservers at American Cloud.** Copy the nameserver values from the instance (your assistant reads them with `get_wordpress_nameservers`; they're also on the instance detail page), set them as your domain's nameservers at the registrar, and American Cloud automatically creates the `A` and `CNAME` records for your site. - **Keep your current DNS provider** and create the records yourself — an `A` record for the apex and a `CNAME` for `www`, exactly as shown in [WordPress hosting](/docs/wordpress/wordpress-hosting). If that domain's DNS is hosted on American Cloud, your assistant can create those records directly with `create_dns_zone` and `create_dns_record` (and set the short TTL on them); if it's hosted elsewhere, the assistant tells you the exact records to add at your provider. ```text Help me cut DNS over to the American Cloud site. 1. Read back the nameservers for my American Cloud WordPress instance. 2. My domain's DNS is currently at . First, walk me through lowering the TTL on the relevant records there to 60 seconds, and let me do that a day before we switch. 3. When I'm ready, guide me through the cutover using the documented method: either repointing my registrar's nameservers at American Cloud, or creating the A and CNAME records per the WordPress hosting doc — at a short TTL. 4. If this domain's DNS zone is hosted on American Cloud, create those records for me directly with a 60-second TTL; otherwise tell me exactly what to enter at my current provider. 5. Then watch resolution until my domain resolves to the new site, and tell me when it's fully propagated. ``` ### What your assistant will do - **Reads the destination nameservers** with `get_wordpress_nameservers` so you have the exact values to set at your registrar — no copying from a screenshot. - **Tells you where to lower the TTL.** It won't assume your DNS lives on the old host; it asks, then guides you to drop the TTL at whichever provider actually serves your domain today, ahead of the switch. - **Follows the documented DNS setup.** It guides the nameserver-repoint path, or the keep-your-provider `A` + `CNAME` path, per [WordPress hosting](/docs/wordpress/wordpress-hosting). When the zone is on American Cloud, it creates the records itself with a short TTL (`create_dns_record`); otherwise it hands you the exact values for your provider. - **Watches propagation** and confirms when your domain resolves to the new site — the moment the migration is "live." ## Phase 5: verify, then cancel the old hosting Don't cancel anything yet. Bring the migrated site fully into production behind your real domain, prove it works, and keep the old shared hosting paid up a little longer as your rollback. Walk the checklist from Phase 1. ```text The domain now points at the American Cloud site. Walk me through verifying it against the Phase 1 inventory before I cancel my old hosting: 1. Load the homepage and each key page over HTTPS on my real domain and confirm they render — compare against the "before" reference we captured. 2. Confirm I can log into wp-admin on the live domain. 3. Test a contact form / transactional email so I know mail is sending. 4. Click through deep links and a few permalinks to confirm the permalink structure carried over (no 404s). 5. Confirm SSL is valid and the site loads without mixed-content warnings. 6. Read back the new site's bandwidth and quota usage so I have a baseline. Give me a go/no-go summary. Only once everything passes, remind me what to do to safely cancel the old shared hosting — and confirm I should NOT cancel the American Cloud site. ``` ### What your assistant will do - **Verifies against the inventory, not from memory.** It loads the homepage and every key page on your real domain over HTTPS and compares them to the Phase 1 "before" capture, confirms wp-admin login, exercises a form so you know mail flows, and clicks deep links to catch permalink 404s. - **Checks the baseline.** `get_wordpress_bandwidth` and `get_wordpress_quota` give you a starting read on usage now that real traffic is arriving. - **Holds the rollback open.** Because you lowered the TTL in Phase 4 and the old host is still up, reverting is just pointing DNS back — fast and complete. The assistant won't suggest decommissioning until you confirm everything passes. ### Cancel the old shared hosting — when you're sure Give it a few days. Watch the new site, confirm forms and email keep working, and make sure nothing still points at the old host. Then cancel the **shared hosting** account — at your old provider's control panel — and leave the American Cloud site running. **`cancel_wordpress` tears down the American Cloud site, not your old host.** It cancels and removes the managed WordPress subscription you just migrated *into*, and its content is deleted and cannot be recovered. In this playbook you almost never want it — the thing you're canceling is the old shared hosting, which lives at your previous provider, not on American Cloud. If your assistant ever proposes `cancel_wordpress`, stop and confirm it's targeting the right thing before approving. If you later need more room — more sites, more bandwidth — you don't migrate again: change the plan in place. Your assistant can list the upgrade options (`list_wordpress_upgrade_packages`) and move you with `change_wordpress_package`, or do it from the dashboard per [WordPress hosting](/docs/wordpress/wordpress-hosting); existing sites and data are preserved. ## Next steps - [WordPress hosting](/docs/wordpress/wordpress-hosting) — the full lifecycle: creating a site, custom domains and DNS, changing plans, and adding sites - [WordPress migrations](/docs/wordpress/migrations) — the documented migration method, and the complimentary white-glove option - [Enterprise WordPress plans](/docs/wordpress/enterprise-plans) — reseller and custom plans for agencies and higher-capacity sites - [Write an AGENTS.md for your project](/docs/deploy-with-ai/agents-md) — capture your conventions so future sessions repeat them - [Things to try with the MCP server](/docs/mcp/use-cases) — more prompt ideas across compute, storage, networking, DNS, and WordPress ## Write an AGENTS.md `AGENTS.md` is a small convention: a markdown file at the root of your repo that AI coding agents read for project-specific instructions. Claude Code, Cursor, and a growing list of agents look for it (Claude Code also reads `CLAUDE.md`) and treat its contents as standing guidance for that repo. Your agent already knows how to build your app — it's been writing the code with you. What it doesn't know is how *you* want it deployed. This drop-in teaches it exactly that: the happy path for shipping this project to American Cloud through the [American Cloud MCP server](/docs/mcp/overview). Once the file is in place, "deploy this" becomes a single prompt, and the agent already knows to price the server before creating it, keep secrets out of your repo, and report back the IP, URL, and monthly cost when it's done. ## What you need first - The [American Cloud MCP server](/docs/mcp/overview) connected to your agent — see the guides for [Claude Code](/docs/mcp/claude-code), [Cursor](/docs/mcp/cursor), or [other clients](/docs/mcp/other-clients). - For actually creating resources: a **read-write API key** from [console.americancloud.com/api-keys](https://console.americancloud.com/api-keys) and the `--allow-writes` flag. The file is safe to add before that — with a read-only key the agent will price and plan but won't create anything. ## Install it Pick whichever is easier: - **Download** `examples/AGENTS.md` from [github.com/American-Cloud/americancloud-mcp](https://github.com/American-Cloud/americancloud-mcp) and drop it at the root of your repo. - **Copy** the block below into a file named `AGENTS.md` at your repo root. (For Claude Code you can name it `CLAUDE.md` instead — Claude Code reads both.) Commit it like any other repo file so every teammate's agent gets the same instructions. Then add your own deploy details under the "Project state" section at the bottom as you go. ## The file This is the complete drop-in, byte-for-byte. The header comment links back to this page and the source repo so anyone who opens the file later knows where it came from. ````markdown # Deploying this project to American Cloud You are an AI coding agent working in this repository. When the user asks to deploy, host, ship, or "put this online" on American Cloud, follow this file. You provision and manage American Cloud infrastructure through the **americancloud** MCP server (tools are snake_case, e.g. `list_regions`, `create_vm`). You run commands on the resulting server over SSH from the terminal. ## Preflight 1. Confirm the **americancloud** MCP server is connected: the `get_server_info` tool should exist. If it does not, stop and tell the user to set it up at https://americancloud.com/docs/mcp/overview, then continue. 2. Call `get_server_info` and check `readOnly`. If it reports `readOnly: true`, you can inspect and price things but cannot create them. Tell the user to switch to a **read-write API key** and add `--allow-writes` to the server's args (see the overview link above), then continue. Do not pretend a create succeeded. 3. Note the enabled service groups from `get_server_info`. If the user needs a group that is not enabled (e.g. `dns`), tell them to add it via `--services`. ## Conventions (always) - **Price before you build.** Before any create, call the matching `get_cost_estimate_*` tool and show the user the monthly estimate. Wait for approval. Never invent or guess prices — only repeat what the tool returns. - **Smallest viable size first.** Pick the smallest package that runs the workload and tell the user it can scale up later (`scale_vm`, `scale_kubernetes_cluster`, `resize_block_storage_volume`). Don't over-provision. - **Confirm before anything destructive.** Deletes, releases, reinstalls, and reverts are irreversible — describe what will be destroyed and get an explicit yes first. - **Never write secrets into the repo.** API keys, object storage keys, kubeconfigs, DB passwords: these go into a server-side env file over SSH (e.g. `/etc/myapp.env`, mode 600) or your secret manager — never into tracked files. Don't echo full secrets back into chat. - **One VM until you need more.** Start with a single VM; add load balancers, more VMs, or Kubernetes only when the user's traffic or architecture calls for it. - **Name resources after this project** so they're identifiable later — use the repo/project name (e.g. `myapp-web`, `myapp-assets`) for VMs, SSH keys, object storage units, and DNS records. ## Canonical deploy flow: web app to a VM 1. **Pick a region.** `list_regions` and choose one near the users (or ask). 2. **Ensure an SSH key.** `list_ssh_keys`. If the user's key isn't there, create one with `create_ssh_key`, or have them add their public key in the console. You'll pass its name in `keypairs` so you can SSH in afterward. 3. **Choose a package and image.** `list_vm_packages` and `list_images` (Ubuntu LTS is a safe default). Start with the smallest package that fits. 4. **Estimate cost.** `get_cost_estimate_vm` with the chosen region, package, specs, and `subscriptionPeriod`. Show the user the monthly number and wait for approval. 5. **Create the VM — with the ports in the same call.** `create_vm` with `name`, `region`, `vmPackage`, `image`, `subscriptionPeriod`, `keypairs`, and `networkAccess.inboundPorts` for the ports you need — typically 22 (SSH), 80 (HTTP), and 443 (HTTPS), `protocol: "TCP"`. This opens both the firewall and the port forwarding on the network's public IP; a firewall rule alone is not enough to reach the VM. Omit `network` to auto-create an isolated network, or pass an existing network UUID. Save the returned VM id and public IP. 6. **Verify or adjust the ports.** `list_firewall_rules` and `list_port_forwarding_rules` on the VM's public IP confirm what's open. To open another port later, add BOTH a `create_firewall_rule` and a `create_port_forwarding_rule` for it (or map the whole IP to the VM with `enable_static_nat`). Use the narrowest `sourceCidrList` that works (`0.0.0.0/0` only for the public web ports). 7. **Wait until reachable.** Poll `get_vm` until it's running, then confirm SSH answers on port 22 before continuing. 8. **Install over SSH.** SSH in and install the runtime (Node, Python, etc.) and a reverse proxy (nginx or Caddy) in front of the app on 127.0.0.1. 9. **Create a systemd service** for the app so it starts on boot and restarts on failure. App config and secrets live in the server-side env file, not the repo. 10. **DNS (if the user has a domain here).** `list_dns_zones`; if the zone exists, `create_dns_record` with an `A` record pointing the hostname at the VM's public IP. (If the domain is elsewhere, give the user the IP and the record to add.) 11. **Enable TLS.** Once DNS resolves, use certbot (or Caddy's automatic TLS) to issue a certificate for the domain and serve HTTPS on 443. 12. **Verify and report.** Curl the public URL and confirm it serves the app. Report back: the VM name and id, public IP, the URL, and the monthly cost estimate from step 4. Offer to record it in "Project state" below. ## Static assets and uploads to object storage Use this when the app serves images/uploads/static files or needs durable storage separate from the VM. 1. `create_object_storage_unit` named after the project, then `create_object_storage_bucket` inside it. Preview with `get_cost_estimate_object_storage` first. 2. `get_object_storage_keys` for the unit — these are **sensitive** S3-style access keys. Put them in the server-side env file, never in the repo. 3. Wire the app via any S3-compatible SDK (AWS SDK, boto3, etc.), pointing it at the unit's S3 endpoint with those keys and the bucket name. ## Kubernetes (only when the user asks for it) For a single app, the VM flow above is simpler and cheaper. Use Kubernetes when the user explicitly wants a cluster or multi-service orchestration. 1. `list_kubernetes_versions` and `list_kubernetes_packages` for options. 2. `get_cost_estimate_kubernetes` and show the user the monthly cost; wait for approval. 3. `create_kubernetes_cluster`, then poll `get_kubernetes_cluster` until ready. 4. `get_kubernetes_cluster_config` for the kubeconfig — **sensitive**, it grants full cluster access. Write it to `~/.kube/` locally (gitignored), never into the repo. 5. Use `kubectl` from the terminal to apply manifests and deploy workloads. ## After deploying Report what was created, where it runs, and the cost estimate. Then suggest the user save the details in the "Project state" section below so the next session (yours or another agent's) starts with the facts instead of rediscovering them. Template: ```markdown ## Project state - Region: us-west-0 - VM: myapp-web (id: ) — , - Open ports: 22, 80, 443 - Domain: myapp.com → A record at - Object storage: myapp-assets unit / uploads bucket (keys in /etc/myapp.env) - Monthly estimate: $XX (from get_cost_estimate_vm on ) - Deploy: systemd service `myapp`, nginx reverse proxy, certbot TLS ``` ## Troubleshooting - **Domain doesn't resolve yet.** DNS changes take time to propagate. Confirm the record with `list_dns_records`, verify with `dig`/`nslookup`, and wait before re-running certbot. - **Connection refused / times out.** The port needs BOTH a firewall rule and a path to the VM. Check `list_firewall_rules` (ingress rule whose `sourceCidrList` includes the caller) and `list_port_forwarding_rules` (the public port forwards to the VM) on the VM's public IP. Add what's missing with `create_firewall_rule` / `create_port_forwarding_rule`, or use `enable_static_nat` to map the IP to the VM one-to-one. - **App isn't serving.** SSH in and check the service: `systemctl status myapp` and `journalctl -u myapp -n 100 --no-pager`. Confirm the reverse proxy is up and pointed at the app's local port. - **VM unreachable.** `get_vm` to confirm it's running; `power_vm` with `action: "reboot"` if it's stuck. ```` ## How it behaves With the file in place, you don't have to spell out the steps each time. When you say "deploy this to American Cloud," the agent reads `AGENTS.md` and: - **Checks the connection and mode first.** It confirms the MCP server is there and whether it's read-only, and tells you what to change rather than failing silently halfway through. - **Shows you the price before it builds.** Every create is preceded by a cost estimate you approve — no surprise bills, no made-up numbers. - **Keeps your secrets out of the repo.** Access keys and configs land in a server-side env file over SSH, not in tracked files. - **Picks a sensible default and scales later.** Smallest viable VM, one server until you need more, resources named after the project so they're easy to find. - **Reports back and remembers.** When it's done you get the IP, URL, and monthly estimate, and the agent offers to record them in the file's "Project state" section so the next session starts with the facts. You stay in control: you approve the cost, you approve anything destructive, and the work happens on your machine through the MCP server you configured. ## Next steps - [MCP server overview](/docs/mcp/overview) — service groups, `--services` scoping, and the read-only-by-default safety model. - [Use American Cloud with Claude Code](/docs/mcp/claude-code) and [with Cursor](/docs/mcp/cursor) — connect your agent. - [Deploy a Next.js app](/docs/deploy-with-ai/deploy-nextjs) — the VM flow above as a full worked example. - [Static assets and object storage](/docs/deploy-with-ai/object-storage) and [run Kubernetes](/docs/deploy-with-ai/kubernetes) — the other deploy-with-AI recipes the file points at. --- # Networking VPCs, firewalls, ACLs, and VPN configuration ## Access control lists (ACLs) Network ACLs are ordered lists of allow/deny rules that you attach to a VPC tier to control what traffic can enter or leave it. Each rule matches a CIDR, protocol, port range, and direction (ingress/egress) and either permits or blocks the matching traffic. In the new portal, ACL lists live under their own top-level page — **Networking → ACL lists** — instead of being nested inside a VPC's settings. ## View existing ACL lists In the left navigation, under **Networking**, select **ACL lists**. ![ACL lists page showing built-in default_allow and default_deny lists](/docs/images/networking/access-control-lists-acls-01.png) Two built-in lists are always present: - **default_allow** — permits all traffic. - **default_deny** — blocks all traffic. You can attach either of these to a [VPC tier](/docs/networking/createmanage-a-virtual-private-cloud-network) directly, or create a custom list with specific rules. ## Create a custom ACL list 1. On the ACL lists page, click **+ Create ACL List** in the top right. 2. In the **Create ACL List** dialog, fill in: - **Name** — a unique name (for example, `my-acl-list`). - **VPC** — pick the VPC this list belongs to. - **Description** — optional. 3. Click **Create ACL List**. ![Create ACL List dialog with Name, VPC, and Description fields](/docs/images/networking/access-control-lists-acls-02.png) The new list opens to its detail page, ready for rules. ![Empty ACL list detail page with Add Rule button](/docs/images/networking/access-control-lists-acls-03.png) ## Add a rule 1. On the ACL list detail page, click **+ Add Rule** in the **ACL Rules** section. 2. In the **Add ACL Rule** dialog, fill in: - **CIDR list** — the source range. Two quick-picks help: - **My IP** — fills in your current public IP as `/32`. - **Anywhere** — fills in `0.0.0.0/0`. - **Protocol** — `TCP`, `UDP`, `ICMP`, `All`, or a numeric protocol number. - **Action** — `Allow` or `Deny`. - **Traffic type** — `Ingress` (into the tier) or `Egress` (out of the tier). - **Number** — the rule's priority. Lower numbers evaluate first. - **Start port** / **End port** — the port range (for TCP/UDP). For ICMP, this becomes **ICMP type** / **ICMP code**. 3. Click **Add Rule**. ![Add ACL Rule dialog with CIDR list, protocol, action, traffic type, number, and port fields](/docs/images/networking/access-control-lists-acls-04.png) The new rule appears in the **ACL Rules** table with its protocol, action, traffic type, CIDR, ports, and a **Delete** action. ![ACL list detail page showing a rule in the ACL Rules table](/docs/images/networking/access-control-lists-acls-05.png) ## Field reference ### Rule number Rule numbers prioritize evaluation. Lower numbers are evaluated first, so put more specific rules above broader ones. ### CIDR list A CIDR-format range (for example, `192.168.1.0/24`) that specifies which source IPs the rule matches. Use the **My IP** and **Anywhere** quick-picks for common cases. ### Action - **Allow** — permit traffic that matches the rule. - **Deny** — block traffic that matches the rule. ### Protocol - **All** — match every network protocol. - **TCP** — connection-oriented, ordered delivery. Requires **Start port** and **End port**. - **UDP** — connectionless. Requires **Start port** and **End port**. - **ICMP** — control messages (ping, unreachable, etc.). Requires **ICMP type** and **ICMP code**. - **Protocol number** — a numeric IANA protocol number. Required fields depend on the protocol. ### Traffic type - **Ingress** — traffic entering the tier. - **Egress** — traffic leaving the tier. ## Attach an ACL to a tier ACLs only take effect once a [VPC tier](/docs/networking/createmanage-a-virtual-private-cloud-network) uses them. On the tier's detail page, click **Change ACL** in the top right and pick the list. ## Delete a list or rule - **Delete a rule** — click **Delete** on the rule's row in the ACL Rules table. - **Delete the list** — click **Delete** in the top right of the ACL list detail page. The built-in `default_allow` and `default_deny` lists cannot be deleted. ## Create and Configure an Elastic Network in American Cloud ## Create The Network - Navigate to [https://app.americancloud.com](https://app.americancloud.com/dashboard) ![](/docs/images/networking/create-and-configure-an-elastic-network-in-01.jpeg) - Click "Networking" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-02.jpeg) - Click "Elastic Network" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-03.jpeg) - Click "+ CREATE ELASTIC NETWORK" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-04.jpeg) - Select the zone in which to build the network. Keeping in mind US-West-0 provides a Premium and Standard cluster where US-West-1 only provides a standard cluster option. Choose based on your compute requirements. - Choose the project of which the network will reside. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-05.jpeg) - **Enter Name**: This field allows for a name to be assigned to the Elastic Network. A unique name is suggested in order to easily differentiate between Elastic Networks, especially in regards to large-scale, multi-network environments. - **Enter Description for Elastic Network**: This field allows for a unique definition of the Elastic Network. - **Gateway**: This field is where to define the default-gateway for the new network. This is what the internal IP address would be on a router or firewall in a traditional network. This is the first-usable address in the IP range (ex. in 10.10.20.0/24, first-usable would be 10.10.20.1). - **Netmask**: This field is for the subnet mask of the IP block based on the desired available IP addresses. Select 'CREATE NETWORK'. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-06.jpeg) - Quick add an instance to the network by selecting the ellipsis menu then "Add Instance". A redirect to instance creation will occur. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-07.jpeg) - View the instances associated with the network by selecting the drop-down arrow. The instances will be depicted as below. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-08.jpeg) ## Manage Public IP Addresses - Manage assigned IP Addresses, Firewall Rules, and Port Forwarding Rules by selecting "Public IP Addresses" from the top menu. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-09.jpeg) - To add a new Firewall rule select "Add Firewall Rule" to the corresponding IP address. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-10.jpeg) - Provide a source CIDR for the Firewall Rule. - Select the protocol required for the new rule. - Provide the protocol specifics ie... start and end port. Select "Add Firewall Rule". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-11.jpeg) - Select "Add Port Forwarding Rule" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-12.jpeg) - Select the VM to add the Port Forwarding Rule to. - Select the protocol for new Port Forwarding Rule. - Identify and input the private start and end ports. Then provide the public start and end ports. These are determined based on your network design. Select "Submit" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-13.jpeg) - The newly created Firewall and Port Forwarding Rules will be displayed in the associated tables below the IP Address. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-14.jpeg) - To delete a rule simply select "Delete Rule" on the associated rule. On the warning/last chance block select "Delete Firewall Rule" to proceed. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-15.jpeg) - American Cloud provides the ability to acquire new IP addresses based on customer's needs. The acquisition of a new IP address cost a standard $1 a month. To acquire select "+ Acquire New IP" in the upper right corner. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-16.jpeg) - In the popup select "Add IP" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-17.jpeg) - Should a requirement for static nat be necessary select "Enable Static NAT" under the associated IP address. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-18.jpeg) - From the drop-down select the VM to enable static nat for. Then select "Enable Static Nat". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-19.jpeg) - Confirm the static nat IP address from the network overview page. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-20.jpeg) - To disable static nat select "Disable Static NAT". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-21.jpeg) ## Egress Rules - Navigate to Egress Rules in the top menu. To add a new rule select "+ Add New Rule" in the top right. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-22.jpeg) - Provide the required fields - Source CIDR for the egress rule. - Input the destination CIDR for new rule. - Lastly choose the protocol and the required protocol information. Select "Add Egress Rule" ![](/docs/images/networking/create-and-configure-an-elastic-network-in-23.jpeg) - The newly created egress rule will be added to the table. To remove the egress rule select "Delete Rule". Then in the warning/last chance block select "Delete" to proceed. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-24.jpeg) ## Remote Access VPN - To enable Remote Access VPN. Select "Remote Access VPN" from the top menu. On the remote access vpn page select the slider bar to activate the vpn. Wait while the connection is being made. The vpn will be available when VPN Status reads "running". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-25.jpeg) - Once the VPN is running, the IP and IPSec pre-shared key will be displayed. Remote access VPN's require user credentials. To add users select "+ Add New User". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-26.jpeg) - In the popup provide a username and password for the user. Save the credentials in a safe location and select "Add User". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-27.jpeg) - Once the user has been added wait for an "Active" state. The user can then access the VPN. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-28.jpeg) - To remove a user select the trashcan icon associated with the user. In the warning/last chance block select "Delete" to proceed. ![](/docs/images/networking/create-and-configure-an-elastic-network-in-29.jpeg) - The user will be removed from the table list. To disable the VPN select the slider bar. Wait as the VPN is disconnected. Once disabled the VPN Status will read "Disabled". ![](/docs/images/networking/create-and-configure-an-elastic-network-in-30.jpeg) ## Create and manage a Virtual Private Cloud network A Virtual Private Cloud (VPC) is a private, isolated network in American Cloud where you control the CIDR block, divide it into tiers (subnets), reserve public IPs, and attach ACLs. This article walks through creating a VPC, adding tiers, and managing public IPs from the new portal. Related topics live in their own articles: - [Access control lists (ACLs)](/docs/networking/access-control-lists-acls) - [Firewall](/docs/networking/firewall) - [Remote access VPN](/docs/networking/remote-access-vpn) - [Creating a VPN customer gateway](/docs/networking/creating-a-vpn-customer-gateway) ## Create a VPC 1. In the left navigation, under **Networking**, select **VPCs**. 2. In the top right of the VPCs page, click **+ Create VPC**. ![VPCs page with the Create VPC button highlighted](/docs/images/networking/createmanage-a-virtual-private-cloud-network-01.png) 3. On the **Create VPC** page, fill in the **Configuration** section: - **Name** — a unique name (for example, `Test-VPC`). - **CIDR** — the VPC's IP range (for example, `10.0.0.0/16`). - **Region** — the region the VPC lives in. - **Description** — optional human-readable note. 4. Review the cost estimate on the right and click **Create VPC**. ![Create VPC page with Name, CIDR, Region, Description, and Cost Estimate panel](/docs/images/networking/createmanage-a-virtual-private-cloud-network-02.png) The new VPC appears in the VPCs list with status **ENABLED**. ![VPCs list showing the new Test-VPC entry](/docs/images/networking/createmanage-a-virtual-private-cloud-network-03.png) > **Note:** A VPC does not delete itself. To stop billing for a VPC, delete it from its detail page. ## Add a tier Tiers are subnets inside the VPC. Each tier has its own gateway, netmask, and ACL. 1. From the VPCs list, click a VPC to open its detail page. 2. In the **Tiers** section, click **+ Add Tier**. 3. In the **Add Tier** dialog, fill in: - **Name** — a tier name (for example, `Web server`). - **Description** — optional. - **Gateway** — the tier's default gateway IP (for example, `10.0.0.1`). - **Netmask** — the tier's subnet mask (for example, `255.255.255.0`). - **ACL list** — pick an existing ACL (`default_allow`, `default_deny`, or a custom list). See [Access control lists (ACLs)](/docs/networking/access-control-lists-acls) for creating custom ACLs. 4. Click **Add Tier**. ![VPC detail page with the Add Tier dialog open](/docs/images/networking/createmanage-a-virtual-private-cloud-network-04.png) The new tier appears in the Tiers section once provisioning completes. ## Manage a tier Click a tier in the Tiers section to open its detail page. The page shows two panels and four actions in the top right. ![Tier detail page with Restart, Change ACL, Rename, and Delete actions](/docs/images/networking/createmanage-a-virtual-private-cloud-network-05.png) - **Network** — CIDR, gateway, and region. - **Configuration** — description, parent VPC, ACL, and creation time. - **Restart** — restart the tier's virtual router (briefly disrupts traffic on this tier). - **Change ACL** — swap the ACL applied to the tier. - **Rename** — change the tier's name. - **Delete** — remove the tier. Detach any VMs first. To attach a VM to a tier, select the tier as the **Network** when [creating a VM](/docs/cloud-compute/cloud-compute). ## Public IPs A VPC includes one source-NAT public IP by default. Reserve additional public IPs from the **Public IPs** section on the VPC detail page. ![Public IPs section showing an allocated IP with state, source NAT, and static NAT columns](/docs/images/networking/createmanage-a-virtual-private-cloud-network-06.png) Each row shows: - **IP address**. - **State** — `ALLOCATED` once available. - **Source NAT** — `Yes` for the VPC's default source-NAT IP; outbound traffic from tier VMs leaves through this IP. - **Static NAT** — VM the IP is statically mapped to, if any. - **Created** date. Click an IP to open its detail page, where you can configure: - **Static NAT** — 1:1 mapping between the public IP and a single VM. - **Port forwarding rules** — forward specific public ports to a VM's private ports. - **Firewall rules** — restrict inbound traffic on the public IP. See [Firewall](/docs/networking/firewall). - **Load balancer rules** — distribute traffic across multiple VMs. See [Load balancer](/docs/load-balancing/load-balancer). To reserve a new public IP, click **+ Reserve IP** at the top of the Public IPs section. ## Creating a VPN Customer Gateway - Navigate to [https://app.americancloud.com](https://app.americancloud.com/network/vpc/e0218977-ea43-4a94-ad85-1dc19efa13d7) ![](/docs/images/networking/creating-a-vpn-customer-gateway-01.jpeg) - Select "Networking" ![](/docs/images/networking/creating-a-vpn-customer-gateway-02.jpeg) - Select "VPN Customer Gateway" from the top menu. ![](/docs/images/networking/creating-a-vpn-customer-gateway-03.jpeg) - Select "+ Add VPN Customer Gateway" ![](/docs/images/networking/creating-a-vpn-customer-gateway-04.jpeg) - **Name** - Input a custom name for the Gateway **Project** - Select the project for the Gateway to reside ## Gateway - Select the public IP address for the Gateway. This should be the public IP of the distant network. Possibly a Firewall device. ## CIDR List - In the context of a gateway, a CIDR list can be used to define the range of IP addresses that are allowed to communicate through the gateway. This can be used as a security measure to restrict access to a network or to specify the range of IP addresses that are allowed to connect to a VPN. The CIDR list can be configured on the gateway device or in the cloud-based network infrastructure to enforce these restrictions. - Select the CIDR List preferred ## IPSEC Pre-shared Key - IPsec (Internet Protocol Security) Pre-shared key (PSK) is a method of authentication used to establish a secure and encrypted communication channel between two devices over a network. PSK is a shared secret key between the two devices that is used to encrypt and decrypt data passing through the communication channel. This method of authentication is commonly used in VPN (Virtual Private Network) connections, where the PSK is shared between the VPN client and server to establish a secure connection. - There are several online tools that generate keys or OPENSSL can be used on the local machine to generate an IPSEC PSK by running: `openssl rand -base64 24` - Create a PSK and add ![](/docs/images/networking/creating-a-vpn-customer-gateway-05.jpeg) - **IKE Encryption** - Internet Key Exchange (IKE) is a protocol used to establish a secure and encrypted connection between two devices in a VPN (Virtual Private Network). Encryption in IKE is used to protect the exchange of security parameters and shared secrets during the establishment of the VPN connection. IKE uses various encryption algorithms, such as AES, DES, and 3DES, to encrypt and protect data transmitted between the devices, ensuring confidentiality, integrity, and authenticity of the data being transmitted. - Input the chosen encryption type ## IKE Hash - Internet Key Exchange (IKE) hash is a cryptographic function used to ensure the integrity of data transmitted between two devices in a VPN (Virtual Private Network) connection. The hash function generates a fixed-size message digest from the input data, which is used to verify that the data has not been modified or tampered with during transmission. IKE supports several hash algorithms, such as SHA-1, SHA-2, and MD5, that can be used to provide different levels of security and performance in the VPN connection. - Input the chosen hash type ## IKE DH - Internet Key Exchange (IKE) Diffie-Hellman (DH) is a key exchange protocol used to establish a shared secret key between two devices in a VPN (Virtual Private Network) connection. DH is used to generate a shared secret key without exchanging the key directly, thus protecting the key from interception. IKE supports various DH groups, such as DH Group 1, 2, 5, 14, 19, 20, 24, etc., that offer different levels of security and performance in the VPN connection. - Input the chosen DH Group ## IKE Version - Internet Key Exchange (IKE) Version is the version of the IKE protocol used to establish a secure and encrypted connection between two devices in a VPN (Virtual Private Network). IKE has undergone several revisions, with each version introducing new features and improvements to the protocol. IKE versions include IKEv1 and IKEv2, with IKEv2 being the most recent version. IKEv2 offers improved security, efficiency, and flexibility over IKEv1, making it the preferred choice for many VPN implementations. - Input the chosen version ## ESP Encryption - Encapsulating Security Payload (ESP) is a protocol used to provide encryption and authentication of data transmitted between two devices in a VPN (Virtual Private Network) connection. ESP encrypts the payload of IP packets, ensuring confidentiality, integrity, and authenticity of the data being transmitted. ESP supports various encryption algorithms, such as AES, DES, and 3DES, that can be used to provide different levels of security and performance in the VPN connection. ESP also provides optional support for data compression and anti-replay protection. - Input the chosen Encryption ## ESP Hash - Encapsulating Security Payload (ESP) hash is a mechanism used to ensure the integrity of data transmitted between two devices in a VPN (Virtual Private Network) connection. The hash function generates a fixed-size message digest from the input data, which is used to verify that the data has not been modified or tampered with during transmission. ESP supports various hash algorithms, such as SHA-1, SHA-2, and MD5, that can be used to provide different levels of security and performance in the VPN connection. - Input the chosen hash ## Perfect Forward Secrecy - Perfect Forward Secrecy (PFS) is a property of cryptographic protocols that ensures that even if the private key of a user is compromised, past communications are still protected. PFS achieves this by generating a new set of public and private keys for each session. This means that even if an attacker gains access to the private key, they will not be able to decrypt previously encrypted messages, providing an additional layer of security to the communication. PFS is commonly used in VPN (Virtual Private Network) and secure messaging protocols. - Input the chosen perfect forward secrecy ![](/docs/images/networking/creating-a-vpn-customer-gateway-06.jpeg) - **IKE Lifetime** - Internet Key Exchange (IKE) lifetime refers to the duration for which the security associations (SA) established during IKE negotiations are valid. An SA is a security mechanism used to ensure the confidentiality, integrity, and authenticity of data transmitted between two devices in a VPN (Virtual Private Network) connection. IKE lifetime can be set by the VPN administrator, and the duration can vary from a few minutes to several hours, depending on the security requirements and network conditions. Once the IKE lifetime expires, the devices renegotiate a new SA to ensure continued secure communication. - Input the chosen lifetime ## ESP Lifetime - Encapsulating Security Payload (ESP) lifetime is the duration for which the encryption and authentication keys used by ESP to secure data transmitted between two devices in a VPN (Virtual Private Network) connection are valid. The ESP lifetime is defined by the VPN administrator and can vary from a few minutes to several hours, depending on the security requirements and network conditions. Once the ESP lifetime expires, the devices renegotiate new keys to ensure continued secure communication. The ESP lifetime can be configured to balance the security and performance requirements of the VPN connection. - Input the chosen lifetime ## Dead Peer Detection - Dead Peer Detection (DPD) is a mechanism used in VPN (Virtual Private Network) connections to detect if one of the peers has become unreachable or unresponsive. DPD monitors the state of the VPN connection and sends periodic requests to the remote peer to confirm its availability. If the peer fails to respond to the requests, the DPD mechanism considers it dead and initiates a new negotiation to establish a new VPN connection. DPD helps to ensure continuous availability and reliability of VPN connections. - Toggle disabled/enabled (Disabled by default) ## Split Connections - Split tunneling is a feature of VPN (Virtual Private Network) connections that allows some traffic to be sent through the VPN tunnel while other traffic is sent directly to the internet. With split tunneling, only the traffic destined for the corporate network is sent through the VPN tunnel, while other traffic, such as browsing the internet, is sent directly to the internet. Split tunneling can reduce the load on the VPN connection and improve the performance of internet-based applications. However, it can also pose security risks, as it can allow unencrypted traffic to bypass the VPN tunnel. - Toggle disabled/enabled (Disabled by default) ## Force UDP Encapsulation of ESP Packets - Force UDP encapsulation of Encapsulating Security Payload (ESP) packets is a technique used in VPN (Virtual Private Network) connections to improve the reliability and efficiency of the ESP protocol over networks that may block or interfere with ESP traffic. By encapsulating the ESP packets within User Datagram Protocol (UDP) packets, the VPN connection can bypass network restrictions and ensure that the ESP traffic is not dropped or modified. The UDP encapsulation can also provide additional security features, such as authentication and anti-replay protection. - Toggle disabled/inabled (Disabled by default) **Select 'ADD VPN GATEWAY** ![](/docs/images/networking/creating-a-vpn-customer-gateway-07.jpeg) - The new gateway will be added to the table. To copy the IPSec preshared-key select the copy icon on the right. Use the trashcan icon to delete the gateway if necessary. ![](/docs/images/networking/creating-a-vpn-customer-gateway-08.jpeg) ## Create Site-To-Site Tip: For more information on creating a VPC, see our [VPC Creation Doc](https://docs.americancloud.com/hc/docs/articles/1722538155-networking-offerings). - Select "VPC" from the top menu. ![](/docs/images/networking/creating-a-vpn-customer-gateway-09.jpeg) - Select the desired VPC network for adding the site-to-site VPN. ![](/docs/images/networking/creating-a-vpn-customer-gateway-10.jpeg) - In the top menu select "Site-to-site VPN" ![](/docs/images/networking/creating-a-vpn-customer-gateway-11.jpeg) - Select the slider bar to activate the site-to-site VPN. Once the VPN is running select "+ Create VPN Connection". ![](/docs/images/networking/creating-a-vpn-customer-gateway-12.jpeg) - In the drop-down select the customer gateway to be used during the connection creation and select "Create VPN Connection" ![](/docs/images/networking/creating-a-vpn-customer-gateway-13.jpeg) - The connection will show in the table below. The state of the connection will change from Pending -> Connecting -> Connected. This process usually takes only a few moments. If failures occur check accuracies on both ends of the connection. ![](/docs/images/networking/creating-a-vpn-customer-gateway-14.jpeg) --- # Account Account management, billing, and support ## American Cloud account Your American Cloud account is the gateway to creating and managing every American Cloud product and service. This article covers the **Account** section of the portal — your profile, users, SSH keys, API keys, and billing pointers. In the left navigation, **Account** expands into five pages: - **My Account** — profile, password, two-factor auth, wallet balance, and usage. - **Billing** — payment methods and invoices. - **API keys** — credentials for the American Cloud API. - **SSH keys** — public keys attached to your account. See [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys). - **Users** — additional users with scoped permissions. ## My Account Open **Account → My Account** to see your wallet, current usage, and profile in one place. ![My Account page showing balance, usage, and profile sections](/docs/images/account/american-cloud-account-01.png) The page is broken into four sections: - **Top metrics** — Wallet balance, Bonus credits, Month-to-date spend, and Projected month total. - **Balance** — wallet and bonus-credit totals. - **Usage** — Month to date, Projected this month, Projected renewals. - **Profile** — Name (edit), Email (Change), Password (Change), and Two-factor auth (Enable). To change a profile field, click the action link next to it (**edit**, **Change**, or **Enable**) and follow the prompts. > **Tip:** Enabling **Two-factor auth** is strongly recommended. The Enable link walks you through pairing an authenticator app. ## SSH keys Open **Account → SSH keys** to add or remove the public keys used when launching VMs and Kubernetes clusters. ![SSH keys page with the Add Key button and a Delete action on an existing key](/docs/images/account/american-cloud-account-02.png) See [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys) for full instructions on adding a key, generating one in the portal, and deleting one. ## Users Open **Account → Users** to invite additional people to your account and scope what they can do. ![Users page showing the account members list and the Add User button](/docs/images/account/american-cloud-account-03.png) The list shows each user's name, email, status (`ACTIVE`, etc.), and roles (a short summary like `14 manage, 14 read`). ### Add a user 1. Click **+ Add User** in the top right. 2. Enter the new user's **Email**, **First name**, and **Last name**. 3. Use the **Permissions** quick-set buttons or set granular per-resource permissions: - **Developer** — applies a sensible developer preset. - **Account Admin** — full access to everything. - **Clear All** — uncheck every box. 4. Set granular permissions in the matrix. Each row has **Read** and **Manage** checkboxes: - **Resources** — Virtual Machines, Kubernetes, Block Storage, Snapshots, Object Storage, Networking, Databases, DNS, WordPress, SSH Keys. - **Account** — Account, API Keys, Billing, User Management. 5. Click **Add User**. ![Add user form showing Email, First/Last name, Permissions quick-sets, and the Read/Manage matrix](/docs/images/account/american-cloud-account-04.png) The user receives an email invitation and appears in the Users list once they accept. ## API keys Open **Account → API keys** to create credentials for the American Cloud API. To create a key, click **+ Add Key** and give it a name. The portal generates a **Client ID** and **Client Secret** and shows them once in an **API Credentials** dialog. ![API keys list with the API Credentials dialog showing Client ID and Client Secret](/docs/images/account/american-cloud-account-05.png) > **Note:** Copy the **Client Secret** immediately — it will not be displayed again. If you lose it, revoke the key and create a new one. Each key row shows its **Client ID**, **Created** date, **Last used**, **Status** (`Active` / `Revoked`), and a **Revoke** action. ## Billing Open **Account → Billing** for payment methods, invoices, and coupons. ## Delete your account To delete your American Cloud account, email [help@americancloud.io](mailto:help@americancloud.io) and a technician will assist. ## Getting Started on American Cloud ## Getting Started on American Cloud Our goal at American Cloud is to be a comprehensive yet simple to use cloud provider. At American Cloud we value our customer's freedom to have their own opinions and beliefs. To this end, American Cloud offers a variety of cancel-proof and user-friendly cloud solutions, all of which can be managed using our custom Web UI. This guide will walk you through signing up for an American Cloud account, accessing the Web UI, creating your first services, and understanding how billing works. 1. Sign Up for an Account 2. Navigate the Web portal 3. Create Your First Compute Instance 4. Create Additional Services 5. Understand Billing 6. Explore American Cloud Guides ### Sign Up for an Account First, you need to create an American Cloud account to start using our services. If you already have a American Cloud account, you can skip to the next section. 1. Navigate to [americancloud.com](http://americancloud.com/) and choose **Sign Up Now**. You will need to choose between **"Organization"** or **"Personal"**. - **Organization**: Enter the organization or company name, full name, email address, phone number, and password. - **Personal**: Enter your full name, email address, phone number, and password. 2. A confirmation email will be sent to the email address you provided. Click the link in that email to confirm your email address. 3. Within the Billing section, fill out the required billing information and choose the initial amount of funds to load to your American Cloud account wallet. Then choose **Proceed to Checkout**. The following page will be for entering payment information. Verify the information is correct and check the box "I agree to pay the above total according to my card issuer agreement". Click **Pay Now**. 4. Most accounts are activated instantly and you can start adding services right away. A small number of accounts may require manual review prior to activation. ### Navigate the Web UI American Cloud's web portal is the gateway to our platform. It enables you to manage your account, view your bills, and manage/add services. Below is a quick breakdown of the Web portal - **Services**: Manage and create Cloud Compute and Kubernetes instances. - **Networking**: Manage and create DNS, load balancers, and networking instances. - **Storage**: Manage and create block storage and snapshots. - **Billing**: Manage and view your payment methods and invoices. - **Support**: Open and manage support tickets. - **Profile**: Manage and update your address, email, phone number, and 2FA. For a full overview of the web portal and its features, see our in depth user guide. ### Create Your First Compute Instance Compute Instances are virtual machines that can be created in a few easy clicks and used for many different applications. You will have the ability to customize your virtual machine to best fit your application computing needs. Use the below guide for further instructions on how to deploy a Compute Instance. - [Deploy a Compute Instance](https://docs.americancloud.com/hc/docs/articles/1722537204-cloud-compute) ### Create Additional Services In addition to Compute Instances, American Cloud has a vast selection of other services that will complete your cloud computing needs. If any of the below would be useful for you, they are only a few clicks away from being created. ### Compute - **ACKS (American Cloud Kubernetes Service)**: Managed Kubernetes clusters that simplify container orchestration. - **Bare Metal (COMING SOON!)**: Dedicated single-tenant hardware for advanced workloads. ### Storage - **Block Storage**: Scalable, high-speed, fault-tolerant, and portable (detachable) storage volumes used to add additional storage to a Compute Instance. - **Object Storage**: Scalability, advanced security features, an S3-compatible API, and easy-to-use management tools. - **Snapshots**: Fully managed automatic daily, weekly, and biweekly snapshots of your American Cloud Compute Instances. ### Networking - **Load Balancers**: Fully configured load balancers with health monitoring and automatic failover. - **Network Access Control Lists (ACLs)**: Customizable ACL lists used to control access to Compute Instances. - **Domain Name Service (DNS)**: A free and comprehensive domain management service included for all American Cloud customers. ### Understand Billing American Cloud services can be paid by either preloaded funds in your wallet or via the primary credit card linked to your American Cloud account. See the below guide for more billing information and pricing. - [Managing Billing in the Web Portal](https://docs.americancloud.com/hc/docs/articles/1722537088-billing) All services are charged even if the instance is in a powered off state. To ensure you are not charged for unused instances please delete the instance. ### Explore American Cloud Guides American Cloud offers a growing library of documentation. This collection covers not only the core products and services offered, but also addresses topics like networking, security, storage, compute instances, and more. For example: quickly learn how to deploy One-Click apps such as WordPress, Grafana, MySQL, Docker, PostgreSQL. American Cloud is here to provide you with an all-in-one cloud computing experience. ## Support ## Do you have a question or need support? Reach out to the team at American Cloud through our chat widget in your customer management portal. Navigate to the menu on the left side of the portal and click "Support." This will bring our chat module onto any page you are working on so you can get the help you need fast. ![](/docs/images/account/support-01.png) Our chat module also has docs which means you don't have to toggle between tabs on your browser. ![](/docs/images/account/support-02.png) ## Just looking for Documentation? You can get to our documentation inside of the chat module. If prefer an expanded view you can click "Docs" in the left hand menu of the customer portal or navigate to [docs.americancloud.com](https://docs.americancloud.com) --- # ACE American Cloud Enterprise private cloud ## ACE Add New User ## Add a New User 1. Log into the ACE environment as Admin 2. In the left-hand navigation bar select ``Accounts`` 3. Select the account to add the new user to. For example `AmericanCloud` in the display below ![](/docs/images/ace/add-new-user-01.png) 4. Once inside the account select `view users` ![](/docs/images/ace/add-new-user-02.png) 5. Select `Add User +` from the top right of the page ![](/docs/images/ace/add-new-user-03.png) 6. Finally add the required information for the user and select `OK`. ![](/docs/images/ace/add-new-user-04.png) 7. Record the new user's credentials into the preferred password management client ## ACE Affinity Groups To further reduce fault tolerance, running multiple instances serving your application/ service together with the load balancer feature provided from the virtual router in ACE, is recommended. In case you have multiple servers running your services, you can assign instances to an Affinity group in ACE. Affinity groups control VM placement by defining whether instances should run together **(affinity)** or apart **(anti-affinity**). **Strict rules** enforce hard placement—VMs **must** follow the rule or fail to deploy—while **non-strict rules** act as preferences that the scheduler will try to honor but may override for availability. Use strict settings when placement is critical (e.g., redundant services on separate hosts), and non-strict when flexibility or uptime takes priority. *Tip! Affinity groups can be attached to instances while creating the instance. You can change an Affinity group of an existing instance from the Instance Details tab. Make sure to stop the instance before changing the Affinity group.* ## Adding New Affinity Groups 1. From the left menu choose **Compute** > **Affinity Groups**, click **Add new Affinity Group**. ![](/docs/images/ace/affinity-groups-01.png) ![](/docs/images/ace/affinity-groups-02.png) ![](/docs/images/ace/affinity-groups-03.png) 2. Provide a name, optionally the description and choose affinity type. ![](/docs/images/ace/affinity-groups-04.png) ![](/docs/images/ace/affinity-groups-05.png) ![](/docs/images/ace/affinity-groups-06.png) ![](/docs/images/ace/affinity-groups-07.png) ## Adding Affinity Group to an Instance that has Already Been Built 1. From the left menu choose **Compute** > **Instances**, click on the instance name. ![](/docs/images/ace/affinity-groups-08.png) ![](/docs/images/ace/affinity-groups-09.png) ![](/docs/images/ace/affinity-groups-10.png) 2. Stop the instance, by clicking on **Stop instance** from the top right options. ![](/docs/images/ace/affinity-groups-11.png) ![](/docs/images/ace/affinity-groups-12.png) 3. Click on **Change Affinity**, from the top right options. ![](/docs/images/ace/affinity-groups-13.png) 4. Select the Affinity group and confirm by clicking **OK**. ![](/docs/images/ace/affinity-groups-14.png) ![](/docs/images/ace/affinity-groups-15.png) ![](/docs/images/ace/affinity-groups-16.png) 5. Make sure to start up your instance again. ![](/docs/images/ace/affinity-groups-17.png) ![](/docs/images/ace/affinity-groups-18.png) ## ACE Creating SSH Key Pair 1. Go to **Compute → SSH Keypairs** ![](/docs/images/ace/creating-ssh-key-pair-01.png) ![](/docs/images/ace/creating-ssh-key-pair-02.png) 2. Click **Create SSH Keypair**. ![](/docs/images/ace/creating-ssh-key-pair-03.png) 3. You'll have two options: - **Create a new keypair:** ACE will generate a keypair and give you the private key. - **Import an existing public key:** If you already have a key, paste the public key here. ![](/docs/images/ace/creating-ssh-key-pair-04.png) 4. After saving, the keypair is associated with your CloudStack account. ![](/docs/images/ace/creating-ssh-key-pair-05.png) 💡 When you launch a VM, select this keypair in the "SSH Keypair" dropdown. ACE will automatically place the public key into the VM's authorized keys. ## Notes - Always back up your private key securely. - CloudStack stores only the **public key**. - The keypair must be selected when creating the VM to be injected into the instance. ## ACE Features American Cloud ACE provides everything offered with the American Cloud CMP to include the below: - Backend API access - Backend GUI access - Custom offerings - Create your own templates - Updated Opentofu/Terraform provider - L3 engineer support access ## Access to CS via GUI & API Users can do just about everything except: - Create/update/delete domains & accounts - Create/update/delete offerings (network, disk, compute, etc...) ## Templates Featured category: AC-OS* = American Cloud curated OS templates Other os templates (legacy) Community category: Newer OS templates AC-APP* = American Cloud CMP(non-ACE) application templates Other CMP(non-ACE) templates (legacy) Appliances ## Offerings Prod-Custom-Standard = Custom CPU & MEM on standard hardware (GUI only for now) Prod-Custom-Premium = Custom CPU & MEM on premium hardware (GUI only for now) Dedicated* = pre-configured CPU & MEM on standare or premium ACKS* = pre-configured CPU & MEM for k8s clusters ## ACE Open Tofu / Terraform Install ## Required Software - LTS version TOFU > **Note:** To visit our github repo [Click Here](https://github.com/American-Cloud/ACE-TF-Examples) **The environment and accounts will be established by American Cloud engineers. Once complete the inital sign-in creds will be provided.** ## Create ACE directory and clone the repo using command ``` git clone https://github.com/American-Cloud/ACE-TF-Examples.git && cd ACE-TF-Examples ``` ## Setup the API environment varibles - Sign into the ACE environment by navigating to `https://gateway00.americancloud.com:8443/client/#/dashboard`. Be sure to add the provided domain. ![](/docs/images/ace/open-tofu-terraform-install-01.png) - Generate and retrieve the API and Secret Keys ![](/docs/images/ace/open-tofu-terraform-install-02.png) ![](/docs/images/ace/open-tofu-terraform-install-03.png) - Once generated add and run the following commands sequencially. ``` export CLOUDSTACK_API_URL="https://gateway00.americancloud.com:8443/client/api" export CLOUDSTACK_API_KEY="" export CLOUDSTACK_SECRET_KEY="" ``` ## Add a SSH keypair to the ACE For further description on generating SSH Keys [Click Here](https://docs.americancloud.com/hc/docs/articles/1722537850-managing-ssh-keys). - In the navigation select `SSH Key Pairs` ![](/docs/images/ace/open-tofu-terraform-install-04.png) - Select `Create A SSH Key Pair` ![](/docs/images/ace/open-tofu-terraform-install-05.png) - Fill in the required information. (The account field is optional and not required for American Cloud purposes.) ![](/docs/images/ace/open-tofu-terraform-install-06.png) ## Setup the VPC or Non-VPC examples by running the repective bash script from within the directory. ``` ./enable_non_vpc_example.sh ``` ``` ./enable_vpc_example.sh ``` - Using the preferred file editor, edit variables/ace.tfvars file after running the above bash scripts and add the keypair name. ``` keypair = "" # Key pair created in UI. Provide name here. ``` ## Initialize TOFU by running the command `Tofu init`. The below readout should be displayed. ``` Initializing the backend... Initializing provider plugins... - Reusing previous version of american-cloud/cloudstack from the dependency lock file - Using previously-installed american-cloud/cloudstack v0.4.2 OpenTofu has been successfully initialized! You may now begin working with OpenTofu. Try running "tofu plan" to see any changes that are required for your infrastructure. All OpenTofu commands should now work. If you ever set or change modules or backend configuration for OpenTofu, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. ``` ## Run the TOFU plan using the command ## `tofu plan -out example-tfplan -var-file variables/ace.tfvars` The following readout will be displayed identifying the resources to be built. ``` OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create OpenTofu will perform the following actions: # cloudstack_egress_firewall.default_egress will be created + resource "cloudstack_egress_firewall" "default_egress" { + id = (known after apply) + managed = false + network_id = (known after apply) + parallelism = 2 + rule { + cidr_list = [ + "0.0.0.0/0", ] + icmp_code = (known after apply) + icmp_type = (known after apply) + ports = [] + protocol = "all" + uuids = (known after apply) } } # cloudstack_firewall.firewall-web will be created + resource "cloudstack_firewall" "firewall-web" { + id = (known after apply) + ip_address_id = (known after apply) + managed = false + parallelism = 2 + rule { + cidr_list = [ + "0.0.0.0/0", ] + icmp_code = (known after apply) + icmp_type = (known after apply) + ports = [ + "2220", ] + protocol = "tcp" + uuids = (known after apply) } } # cloudstack_instance.web_net_1[0] will be created + resource "cloudstack_instance" "web_net_1" { + display_name = "ACE-Test-net-1-web-0" + expunge = true + group = (known after apply) + id = (known after apply) + ip_address = (known after apply) + keypair = "silverbullet" + name = "ACE-Test-net-1-web-0" + network_id = (known after apply) + project = (known after apply) + root_disk_size = 20 + service_offering = "ACE 2 vCPU 4GB Ram - z0" + start_vm = true + tags = { + "environment" = "staging" + "role" = "net-1-web" } + template = "AC-OS-ubuntu-22.04-2023-11-15T15-39-13Z" + zone = "zone0" } # cloudstack_ipaddress.pub-ip will be created + resource "cloudstack_ipaddress" "pub-ip" { + id = (known after apply) + ip_address = (known after apply) + is_portable = false + is_source_nat = (known after apply) + network_id = (known after apply) + project = (known after apply) + tags = (known after apply) + zone = "zone0" } # cloudstack_network.ace-network-1 will be created + resource "cloudstack_network" "ace-network-1" { + acl_id = "none" + cidr = "10.0.1.0/24" + display_text = (known after apply) + endip = (known after apply) + gateway = (known after apply) + id = (known after apply) + name = "ace-network-1" + network_domain = (known after apply) + network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService" + project = (known after apply) + source_nat_ip_address = (known after apply) + source_nat_ip_id = (known after apply) + startip = (known after apply) + tags = (known after apply) + zone = "zone0" } # cloudstack_port_forward.web_net_1[0] will be created + resource "cloudstack_port_forward" "web_net_1" { + id = (known after apply) + ip_address_id = (known after apply) + managed = false + forward { + private_port = 22 + protocol = "tcp" + public_port = 2220 + uuid = (known after apply) + virtual_machine_id = (known after apply) } } Plan: 6 to add, 0 to change, 0 to destroy. Changes to Outputs: + pub_ip = (known after apply) ─────────────────────────────────────────────────────────────────────────────── Saved the plan to: example-tfplan To perform exactly these actions, run the following command to apply: tofu apply "example-tfplan" ``` ## Apply the TOFU plan by running `tofu apply example-tfplan`. Once ran the resource changes will be displayed along with the Public IP to utilize when connecting to the instances. ``` Apply complete! Resources: 6 added, 0 changed, 0 destroyed. Outputs: pub_ip = "x.x.x.x" ``` - SSH into the machine using the following guidelines. ``` ssh -p 222X cloud@X.X.X.X ``` > **Note:** The port number `222X` the `X` is the index number of the server created. In the `variables/ace.tfvars` you will set the `count` of how many servers to create. If the count is `1`, then the port number would be `2220` as the indexing count starts at `0` In the `VPC` example the port forwarding is only setup on `web_net_1` instances. You will need to adjust VPC ACL rules to access instances on the `web_net_2`, as well as putting a SSH private key on the instances you are port forwarding to, so that you can SSH from `web_net_1` instances to `web_net_2` ## Lastly use the following command to cleanup the environment ``` tofu plan --destroy -out example-tfplan -var-file variables/ace.tfvars ``` - A readout will display all resource changes that will take place once applied ``` OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy OpenTofu will perform the following actions: # cloudstack_egress_firewall.default_egress will be destroyed - resource "cloudstack_egress_firewall" "default_egress" { - id = "89ed85c4-50bc-4e18-91ae-dcfbc9db31c9" -> null - managed = false -> null - network_id = "89ed85c4-50bc-4e18-91ae-dcfbc9db31c9" -> null - parallelism = 2 -> null - rule { - cidr_list = [ - "10.0.1.0/24", ] -> null - icmp_code = 0 -> null - icmp_type = 0 -> null - ports = [] -> null - protocol = "all" -> null - uuids = { - "all" = "1d297874-affe-4795-956a-f6f0e384e54e" } -> null } } # cloudstack_firewall.firewall-web will be destroyed - resource "cloudstack_firewall" "firewall-web" { - id = "7bf925eb-5a65-4ce3-8e04-7840334a73df" -> null - ip_address_id = "7bf925eb-5a65-4ce3-8e04-7840334a73df" -> null - managed = false -> null - parallelism = 2 -> null - rule { - cidr_list = [ - "0.0.0.0/0", ] -> null - icmp_code = 0 -> null - icmp_type = 0 -> null - ports = [ - "2220", ] -> null - protocol = "tcp" -> null - uuids = { - "2220" = "77905ac1-7d8f-459e-b812-8ba8b02a7916" } -> null } } # cloudstack_instance.web_net_1[0] will be destroyed - resource "cloudstack_instance" "web_net_1" { - display_name = "ACE-Test-net-1-web-0" -> null - expunge = true -> null - id = "afd6d90e-fc30-416b-8e1e-c0d8ee912188" -> null - ip_address = "10.0.1.244" -> null - keypair = "silverbullet" -> null - name = "ACE-Test-net-1-web-0" -> null - network_id = "89ed85c4-50bc-4e18-91ae-dcfbc9db31c9" -> null - root_disk_size = 20 -> null - service_offering = "ACE 2 vCPU 4GB Ram - z0" -> null - start_vm = true -> null - tags = { - "environment" = "staging" - "role" = "net-1-web" } -> null - template = "AC-OS-ubuntu-22.04-2023-11-15T15-39-13Z" -> null - zone = "zone0" -> null } # cloudstack_ipaddress.pub-ip will be destroyed - resource "cloudstack_ipaddress" "pub-ip" { - id = "7bf925eb-5a65-4ce3-8e04-7840334a73df" -> null - ip_address = "172.252.211.166" -> null - is_portable = false -> null - is_source_nat = true -> null - network_id = "89ed85c4-50bc-4e18-91ae-dcfbc9db31c9" -> null - tags = {} -> null - zone = "zone0" -> null } # cloudstack_network.ace-network-1 will be destroyed - resource "cloudstack_network" "ace-network-1" { - acl_id = "none" -> null - cidr = "10.0.1.0/24" -> null - display_text = "ace-network-1" -> null - gateway = "10.0.1.1" -> null - id = "89ed85c4-50bc-4e18-91ae-dcfbc9db31c9" -> null - name = "ace-network-1" -> null - network_domain = "cs260cloud.internal" -> null - network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService" -> null - tags = {} -> null - zone = "zone0" -> null } # cloudstack_port_forward.web_net_1[0] will be destroyed - resource "cloudstack_port_forward" "web_net_1" { - id = "7bf925eb-5a65-4ce3-8e04-7840334a73df" -> null - ip_address_id = "7bf925eb-5a65-4ce3-8e04-7840334a73df" -> null - managed = false -> null - forward { - private_port = 22 -> null - protocol = "tcp" -> null - public_port = 2220 -> null - uuid = "ed849b59-da71-4990-8563-fb8fee09036c" -> null - virtual_machine_id = "afd6d90e-fc30-416b-8e1e-c0d8ee912188" -> null } } Plan: 0 to add, 0 to change, 6 to destroy. Changes to Outputs: - pub_ip = "172.252.211.166" -> null ─────────────────────────────────────────────────────────────────────────────── Saved the plan to: example-tfplan To perform exactly these actions, run the following command to apply: tofu apply "example-tfplan" ``` - Next apply the plan ``` tofu apply example-tfplan ``` - Once complete a readout will display the changed resource ``` Apply complete! Resources: 0 added, 0 changed, 6 destroyed. ``` ## ACE VPN Portal Upon receipt of the ACE portal credentials navigate to [ace-vpn.americancloud.com](https://ace-vpn.americancloud.com/) and log in to access the remote access dashboard. Once logged in it's possible to manage the organization's users. Below is a layout explanation of the User Interface. ![](/docs/images/ace/vpn-portal-01.png) 1. The dropdown menu provides a means to access and edit the user account, a VPN connections, or to log out of the session. 2. This button allows quick access to the current user's VPN client profiles. 3. This button allows the management of additional end-users in the organization that may also require access to the ACE environment. 4. This section allows further information on the ACE features, setup and usage of the ACE environment, installation instructions for the WireGuard client to connect with based on OS, and additional CloudStack documentation for reference. ## User Account To access the user account, reset a password, and enable Two-Factor Authentication, use your dropdown menu and choose Edit Account: ![](/docs/images/ace/vpn-portal-02.png) The next screen will allow for confirmation of the user's contact information, change the user's password, and toggle Enable 2FA. ![](/docs/images/ace/vpn-portal-03.png) ## 2FA SMS Once Enable 2FA is toggled on and the SAVE button is pressed, the 2FA type will be available. Choose the method(s) available. ![](/docs/images/ace/vpn-portal-04.png) When you choose your 2FA type and SAVE, a Manage `type` link will be made available for testing and confirm that the method is functioning properly: ![](/docs/images/ace/vpn-portal-05.png) Access the Manage page and confirm the method is functioning properly prior to logging out of your session. ![](/docs/images/ace/vpn-portal-06.png) ## 2FA TOTP For TOTP, an auto-generated seed will be provided. To accept this seed, choose SAVE NEW SEED button, or to have a different one generated choose GENERATE RANDOM SEED. ![](/docs/images/ace/vpn-portal-07.png) Once the SAVE NEW SEED button is pressed the Verification option will become available. Save your seed to the TOTP application or scan the QR code in the application and enter the TOTP 6-digit code and choose VERIFY NEW CODE. ![](/docs/images/ace/vpn-portal-08.png) ## Remote Access VPN Clients To set up a remote access VPN client(s) expand the dropdown menu and choose VPN Clients or use the MANAGE VPN CLIENTS button on the dashboard main page (position 2). ![](/docs/images/ace/vpn-portal-09.png) The VPN USER-PORTAL page provides the ability to add, edit, and delete your VPN configurations. ![](/docs/images/ace/vpn-portal-10.png) To create a new peer connection choose ADD NEW PEER from the VPN USER-PORTAL page. This will generate a Public Key and provide an option to give the connection a friendly Identifier. Then select SAVE. Use nicknames that are easy for you to find and manage as needed, like 'officeworkstation', 'mobilephone', etc. ![](/docs/images/ace/vpn-portal-11.png) Now a Peer will be listed in the VPN User-Profile page. By selecting the peer it provides a download option of the automatically generated configuration file to import into the local WireGuard client. Choose INFO to access the Download option for the specific Peer being loaded on the current host. This will also display a QR code that can be scanned from a mobile device. Choose INFO at the front of the Profile to view the additional information. ![](/docs/images/ace/vpn-portal-12.png) Download the client VPN profile and import it into the WireGuard Client. There is an EDIT option as well at the end of each profile to change its nickname identifier or delete the profile. ![](/docs/images/ace/vpn-portal-13.png) ## Additional User Setup In order for other end-users within the organization to access the ACE environment they will need to have their own user account within the ACE-VPN portal to create their own VPN Profiles. From the main dashboard choose MANAGE USERS (option 3). This will provide a list of accounts in the organization. Additionally, the page provides the ability to create, edit, or delete users as needed. Only MANAGERS of the organization have this access and ability. ![](/docs/images/ace/vpn-portal-14.png) Choose ADD NEW USER from the VPN USERS page and fill out the new user information. When finished, SAVE the account and the new user will have access to this portal and may create, edit, and delete their own VPN Peers. ![](/docs/images/ace/vpn-portal-15.png) More information (Option 4 section of the dashboard) is provided for quick links to additional content, further reading, and ACE online documentation. ![](/docs/images/ace/vpn-portal-16.png) Your data is your own and by utilizing the American Cloud Enterprise VPN Portal you are in control of who accesses your data, wherever they may be. ## Available Templates/ISO's Pre-configured virtual machine images (OS or application-based) used to quickly deploy consistent environments. These may include Linux distributions (e.g., Ubuntu, Rocky), Windows Server versions, or full application stacks (e.g., GitLab, WordPress, Nextcloud). ## Operating Systems - **Ubuntu**: 16.04, 20.04, 22.04, 24.04 (incl. KDE/XFCE) - **Debian**: 11.6, 12 - **Rocky Linux**: 8, 9, 9.2, 9.5 - **CentOS**: 8, 9 - **Fedora**: 37, 38 - **Windows Server 2019**: Multiple builds - **Talos**: 1.10 - **OpenBSD**: 7.4 ## Kubernetes - CAPI on Ubuntu 20.04 (KUBE, K8S-1.27-CAPI) ## Applications - **Docker-based**: WordPress, Nextcloud, Supabase, Jitsi - **GitLab CE**: 16.7.2, 17.4.2, 17.11.0 - **Other Apps**: Coolify v4, CloudPanel v2, Docker (latest) ## ISO's Bootable disk images used for installing operating systems, drivers, or tools. ## Operating Systems - **Windows Server**: 2019, 2022 - **Ubuntu**: 22.04.1 Live Server ## Tools / Drivers - xs-tools.iso - vmware-tools.iso - Virtio ISO - Virtio New ## Kubernetes Binaries (ISOs) - Versions: 1.27.3, 1.26.6, 1.25.0, 1.24.0, 1.23.3, 1.22.6 ## Creating a Windows Server 2019 Demo Network 1. Navigate to [https://gateway00.americancloud.com:8443/client](https://gateway00.americancloud.com:8443/client) 2. Login to your ACE environment using the credentials from the Knox Vault. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-01.jpeg) ## Build Network - First, create an Isolated network to build your VM's on. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-02.jpeg) - Click "Add network" ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-03.jpeg) - Provide the required information: **Name:** Provide a name based on your required naming convention **Description:** Helps to distinguish between networks **Zone:** This should be the zone you're wanting to build the VM's in. **Domain:** Since building an isolated network be sure to select the domain. **Account:** Once the domain is selected an additional box will display labeled account. Select the appropriate account for the network. **Network Domain:** Leave Blank **Network Offering:** Select [[Offering for Isolated networks with Source Nat service enabled]]. **External ID:** Leave Blank ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-04.jpeg) - The remainder of the boxes can be left blank unless building the network for a VPC. Select 'OK'. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-05.jpeg) - Click "Win-Demo-Net" or the network built. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-06.jpeg) - Click "Public IP addresses" ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-07.jpeg) - To begin we'll be missing an IP for our network. Following the first build ACE will assign an IP to the machine and enable that IP as the source NAT. On this page additional IP's can be acquired and managed for sequential machines. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-08.jpeg) ## Build the Instance - Click [[cloud/instance]] icon from the left navigation bar and select [[instances]]. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-09.jpeg) - Select [[Add Instance +]] toggle. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-10.jpeg) - Select the zone the VM should reside in. The zone should mirror the zone of the network to build on. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-11.jpeg) Alert: Currently Zone 0 offers a standard and premium node while Zone 1 only offers standard. - Click the "Search" field. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-12.jpeg) - Type "wind [[enter]]" This will narrow down the selection of offerings presented. - Click "Community" ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-13.jpeg) - Click [[AC-OS-Windows-Server-2019-Standar-2024-07-01]] is the newest template of windows. Select it by the radio button to the left. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-14.jpeg) - If selecting an offering for zone0, you'll see two different options. An [[ACE-1C32-1R64-P]] and [[ACE-1C32-1R64-S]] where P= premium and S= standard. Zone 1 as stated above will only have the standard cluster. Select the appropriate offering. The ones listed above are custom offerings, allowing you to provision the vm more to your needs. We also have several default offerings. Once you've selected the CUSTOM service offering select the CPU cores from 1-32 and RAM from 1000-64000. This can all be scaled at a later date if necessary. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-15.jpeg) - Once CPU/RAM have been selected. You'll want to decide upon the size of the root disk. While looking at the VM build in the right-hand pane. You can identify the default disk offering of 50 GB. If your project requires more of a root disk. Select [[Override root disk offering]] toggle. In the disk offerings section select [[CustomLocal]]. Then scale the root disk to the appropriate size. If additional data disk are required select the size in section 4. Data Disk. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-16.jpeg) - Select the network for the VM. For the initial build we select the network we built in the first steps. Under default network we can leave the IP Address and MAC Address blank as they'll be issued via Cloudstack. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-17.jpeg) - The additional blocks are informational and optional. Fill them in as necessary and select [[Launch Instance]]. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-18.jpeg) - The machine will launch and move to a starting status. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-19.jpeg) - Once the machine goes to a running state, the password will be presented. Be sure to copy and securely store this password for SSH purposes if you haven't built a ssh key. You can close the popup once copied. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-20.jpeg) Tip: Congrats you've built your Windows machine. ## Access Machine - Click "VM-12c7eb61-e7ea-4b26-80f2-8ca4d77b5bb2" ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-21.jpeg) - Click this icon. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-22.jpeg) - Initial a new password for the Administrator is required. Select 'OK'. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-23.jpeg) - Once the password has been excepted and changed successfully. Select 'OK' ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-24.jpeg) - You'll be logged in and directed to the Server Manager for windows 2019 datacenter. ![](/docs/images/ace/creating-a-windows-server-2019-demo-network-25.jpeg) Tip: Additional to the ACE console is remote access. Remote access is a more desirable connection. [Made with Scribe](https://scribehow.com/shared/Creating_a_Windows_Server_2019_Demo_Network__eP9CjgFQR6OqWfIdRqILYQ) ## Enable Static NAT 1. Navigate to [https://gateway00.americancloud.com:8443/client](https://gateway00.americancloud.com:8443/client) 2. This is the VPC you built. Which looks good. ![](/docs/images/ace/enable-static-nat-01.png) 3. Click "Public IP addresses" to list the already allocated IP Addresses. ![](/docs/images/ace/enable-static-nat-02.png) 4. The below image identifies the IP addresses available. One is identified as source nat. Leave that one as is. The other can be utilized as needed. ![](/docs/images/ace/enable-static-nat-03.png) 5. We'll select the IP not being utilized. ![](/docs/images/ace/enable-static-nat-04.png) 6. That will bring us to the IP management page. We can assign an IP by selecting the '+' icon in the upper right as depicted. ![](/docs/images/ace/enable-static-nat-05.png) 7. Once selected a list of currently running vm's will appear. Simply select the VM to enable static nat for. ![](/docs/images/ace/enable-static-nat-06.png) *There are no VM's listed above b/c you've not built any or have destroyed what you had built.* ## Unique IPs 1. If you'd like multiple servers with unique IP's, to acquire a new IP click "Acquire new IP" ![](/docs/images/ace/enable-static-nat-07.png) 2. The system will automatically select the first available IP for distribution. By selecting the drop-down arrow you can select from a list of available IP addresses. ![](/docs/images/ace/enable-static-nat-08.png) *Once the IP is acquired follow the previous steps to enable static nat.* ## Getting Started With ACE This guide provides a quick view of how to start using your ACE environment and how to build your first VM. For more detailed articles click the following links: - [KNOX User Guide](https://docs.americancloud.com/hc/docs/articles/1724695918-knoix) - [ACE VPN Portal](https://docs.americancloud.com/hc/docs/articles/1724695870-ace-vpn-portal) - [Adding New Users](https://docs.americancloud.com/hc/docs/articles/1727808068-ace-add-new-user) - [Installation of Open Tofu/Terraform](https://docs.americancloud.com/hc/docs/articles/1722538038-ace-install-and-use) - [Affinity Groups](https://docs.americancloud.com/hc/docs/articles/1753881226-ace-affinity-groups) - [Templates and ISO's](https://docs.americancloud.com/hc/docs/articles/1753888040-available-templates) - [SHH Key Pairs](https://docs.americancloud.com/hc/docs/articles/1753888977-ace-creating-ssh-key-pair) ## Getting Started with ACE After connecting to the [ACE VPN](https://docs.americancloud.com/hc/docs/articles/1724695870-ace-vpn-portal) Navigate to [https://gateway00.americancloud.com:8443/client/#/dashboard](https://gateway00.americancloud.com:8443/client/#/user/login?redirect=/dashboard). Enter your username, password and domain ID to log in on the ACE panel. - Tip! These Credentials are NOT the same as your **[*AmericanCloud.com*](https://americancloud.com/) customer portal. These are the credentials that were shared with you in your KNOX Vault. ([*https://knox.americancloud.io/#/login*](https://knox.americancloud.io/#/login)) Click "Login" ![](/docs/images/ace/getting-started-with-ace-01.png) ## Creating a Virtual Machine and Isolated Network - *Tip! We recommend adding a network or VPC before building your VM.* ### Adding an Isolated Network An isolated network can be deployed with different services like an HAproxy load balancer in the virtual router or source nat to communicate with other networks or a simple layer 2 network. A **Network Offering** in ACE defines how the isolated network is set up and which services to include with its deployment. **`Offering For Isolated Networks with Source Nat Service Enabled`** is our default offering that creates a single virtual router with Source Nat service enabled and egress traffic blocked by default. It provides the following services `[DHCP, firewall, port forwarding, Source NAT, Static NAT, User data, DNS, Load balancer and VPN]` - *We also have an offering used for our Kubernetes Service which is explained in a separate article.* From the Dashboard Select "Network" ![](/docs/images/ace/getting-started-with-ace-02.png) Select "Guest Networks" ![](/docs/images/ace/getting-started-with-ace-03.png) Click "Add Network" ![](/docs/images/ace/getting-started-with-ace-04.png) Name your Network and Add a Description if Needed ![](/docs/images/ace/getting-started-with-ace-05.png) Select your Domain ![](/docs/images/ace/getting-started-with-ace-06.png) Select the Zone where you will be building your Network and VM ![](/docs/images/ace/getting-started-with-ace-07.png) Select "`Offering for Isolated networks with Source Nat service enabled`" ![](/docs/images/ace/getting-started-with-ace-08.png) Click "OK" ![](/docs/images/ace/getting-started-with-ace-09.jpeg) Your Isolated Network has Been Allocated. The network can be viewed by going to **Network** > **Guest networks** ![](/docs/images/ace/getting-started-with-ace-10.jpeg) ## Creating a New Virtual Machine From the ACE Dashboard panel choose **Compute > Instances**, click **Add Instance** ![](/docs/images/ace/getting-started-with-ace-11.png) Select "Instances" ![](/docs/images/ace/getting-started-with-ace-12.png) Select "Add Instance" ![](/docs/images/ace/getting-started-with-ace-13.png) Choose the zone where you will be building your VM and have already built your Network ![](/docs/images/ace/getting-started-with-ace-14.png) Choose a **Template** or **ISO.** *Templates are images containing an OS used to boot up the server, or boot from an ISO a virtual DVD/ CD that can be uploaded separately. Too see a list of all of our templates *[*Click Here.*](https://docs.americancloud.com/hc/docs/articles/1753888040-available-templates) ![](/docs/images/ace/getting-started-with-ace-15.png) ![](/docs/images/ace/getting-started-with-ace-16.png) Select a Compute Offering for your Instance, which determines how many CPU cores and memory is allocated to the server or Create a custom offering. ![](/docs/images/ace/getting-started-with-ace-17.png) ![](/docs/images/ace/getting-started-with-ace-18.png) ![](/docs/images/ace/getting-started-with-ace-19.png) Override the Root Disk Offering if needed ![](/docs/images/ace/getting-started-with-ace-20.png) ![](/docs/images/ace/getting-started-with-ace-21.png) Select the **Network** in which the server will be deployed that was created earlier in this tutorial. ![](/docs/images/ace/getting-started-with-ace-22.png) You can Choose to associate an **SSH key** pair to the server. If you created SSH key pairs under the **Account** section they will show up here. ![](/docs/images/ace/getting-started-with-ace-23.png) *Tip! Select additional options under **Advanced Mode**, like boot type, add user data and/or select an **Affinity Group** to place the virtual machine in.* - *These options are not required but can help with setting up the virtual machine in a more specific state.* Click "Launch Instance" ![](/docs/images/ace/getting-started-with-ace-24.png) After the server is deployed, you will see the password show up in the panel if the password set has been configured in the chosen **Template**. Make sure to the save the password in a password manager of your choice. ## Knox **Knox is American Cloud's self-hosted credential platform based off of the trusted BitWarden Password Management application. As such, Knox provides a secure means for American Cloud to share and manage sensitive data with our clients via customized organizations and vaults. Knox provides a combination of both asymmetric and asymmetric encryption that protects sensitive information as it is shared, as well as organizational policies that ensure compliance with AICPA SOC2 Type 2 / Privacy Shield, GDPR, and CCPA regulations. All logins stored on Knox reside in an encrypted vault, utilizing AES-CBC 256 bit encryption, salted hashing, and PBKDF2 SHA-256 algorithms.** **Security is tantamount when it comes to credential and authentication management and American Cloud feels a solution as strong as Fort Knox is what it takes to deliver this.** ## Creating Account Knox is self hosted and completely separate from BitWarden. Please make sure to follow these steps even if you are already an active user of VaultWarden or BitWarden. There is information later in this document that goes over connecting this account to your current BitWarden Clients and Account Switching ## Invitation When it’s necessary for Clients of American Cloud to share information such as secure logins with an engineer or vice versa an invite to join a secure Organization in Knox will be initiated. *Employees of American Cloud will never ask for login information over the phone, email, or text.* Once you have opened the email from “Knox” with the email address ([ops@americancloud.us](mailto:ops@americancloud.us)) click the “Join Organization Now” button.![](/docs/images/ace/knox-01.jpeg) ## Join the Organization ***Important:*** For new user’s of American Cloud’s Knox Create a new account using the “Create Account” button. Even if you have a current BitWarden or VaultWarden account DO NOT try to Log In, Knox is a unique Vault with its own unique Domain([knox.americancloud.io](http://knox.americancloud.io)). ![](/docs/images/ace/knox-02.jpeg) ## Master Password After clicking the “create account” button you will be taken to the following screen. Here you will be able to create your username and master password. ***Important:*** If you forget your master password it will be unrecoverable. The only way to allow you back into the vault will be by having an Admin from American Cloud remove you from Knox completely and you will need to create a new account after being re-invited.![](/docs/images/ace/knox-03.jpeg) ## Logging In When you want to log into Knox you will navigate in your web browser to: [knox.americancloud.io](http://knox.americancloud.io). There you will be able to enter your email address and your master password. ***There will be instructions at the end of this document detailing how to add this domain to your bitwarden extensions and client if you are already a BitWarden user.*** ![](/docs/images/ace/knox-04.jpeg) ![](/docs/images/ace/knox-05.jpeg) ## 2FA and SOC-2 Compliance In order to be fully SOC-2 compliant we require all users to set up two factor authentication. If 2FA is not set up within 24 hours you will be removed from the organization. In order to gain access to the organization you will need to set up 2FA and an Admin from American Cloud will have to re-invite you. Along with that personal information should not be shared or stored in Knox. We have disabled the My Vault option. If you store any information in “My Vault” prior to joining the Organization you were invited to, it will be destroyed and unrecoverable upon joining the Organization. ## Setting Up 2FA Navigate to Account Settings once you are logged in ![](/docs/images/ace/knox-06.jpeg) Choose Security from the Account Setting menu and choose a form of 2FA. Any type of 2FA you choose will work. ![](/docs/images/ace/knox-07.jpeg) ## Account Switching If you have accounts on multiple servers, for example a previous bitwarden account and now `knox.americancloud.io`, use the **server selector drop down** that is located on the login screen and select the **Self-hosted** menu to change the **Server URL** to the URL for the account. ![Self-hosted domain selector](/docs/images/ace/knox-08.png)*Self-hosted domain selector* In this example, for American Cloud you would use `knox.americancloud.io` as the domain. --- # Marketplace apps One-click application deployments ## Cloudpanel ![](/docs/images/marketplace/cloudpanel-01.png) ## Cloudpanel CloudPanel is a web-based control panel designed to streamline and manage cloud infrastructure. It offers a user-friendly interface for configuring, monitoring, and optimizing cloud resources, simplifying tasks such as server provisioning, scaling, and security management. By centralizing control over diverse cloud services, CloudPanel enhances efficiency, reduces manual interventions, and ensures better resource utilization. It supports various cloud providers and facilitates seamless collaboration among teams. With features like automated backups, user management, and real-time analytics, CloudPanel empowers organizations to harness the full potential of their cloud environment while minimizing complexity. ## Create Instance 1. Login to the Web Portal with a valid American Cloud account. 2. On the left navigation column choose 'Cloud Compute'. 3. Click on "Create an Instance" select the "Project" and click "Proceed" 4. Select your location and network. Under "Choose Server Image" select "Marketplace Apps" tab and choose "Cloudpanel" ![](/docs/images/marketplace/cloudpanel-02.png) ![](/docs/images/marketplace/cloudpanel-03.png) 5. Choose a server size. ![](/docs/images/marketplace/cloudpanel-04.png) 6. ***Optional*** Generate or add SSH key. Click on Review and Deploy once reviewed click on Deploy Now. 7. ***Optional*** While the Wordpress VM is deploying a DNS record can be added if you already know what domain you are going to use for your site. The Public IP can be found under the Overview of the VM. ![](/docs/images/marketplace/cloudpanel-05.png) **Note:** DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues. If desired American Cloud offers complimentary DNS Management. Add your domain to the DNS Management section in the left navigation menu on American Cloud. Afterwards go to your registar's website and point your domain to the American Cloud nameservers: [ns1.americancloud.org](http://ns1.americancloud.org/) and [ns2.americancloud.org](http://ns2.americancloud.org/). Inside the American Cloud UI navigate to the DNS Manager and create the appropriate A records. **Example Below:** Inside American Cloud DNS Management click the edit pencil for your new domain and create the appropriate A records, remember to swap 0.0.0.0 for your new Public IP address. ![](/docs/images/marketplace/cloudpanel-06.png) 8. Navigating to the [https://publicip:8443](https://publicip:8443/) via a browser will display the cloudpanel admin user setup page. Provide the necessary information ensuring to save the user/password. ![](/docs/images/marketplace/cloudpanel-07.png) 9. Using the credentials sign into the newly built cloud panel For further information on operating cloudpanel, visit the [cloudpanel docs here](https://www.cloudpanel.io/docs/v2/introduction/). ## Deploying a Coolify instance [Coolify](https://coolify.io) is an open-source, self-hostable Platform as a Service (PaaS) — an alternative to Heroku, Netlify, and Vercel that lets you deploy applications, databases, and services on your own infrastructure. American Cloud's marketplace ships a one-click Coolify image so you can be up and running in a few minutes. ## Create the Coolify VM 1. In the left navigation, under **Compute**, select **Virtual machines**, then click **+ Create VM** in the top right. 2. On the **Create virtual machine** page, fill in the **Configuration** section: - **VM name** — for example, `coolify`. - **Region** — for example, **US West (Zone 1)**. - **Package type** — **Standard Custom**. - **Deploy from** — choose the **Marketplace App** tab. - **Marketplace app** — **Coolify v4.1.1** (or the latest available). - **Operating system** — the recommended OS shown by the marketplace image (for example, **Ubuntu 26.04 LTS (recommended)**). ![Create virtual machine page with Marketplace App tab and Coolify selected](/docs/images/marketplace/deploying-a-coolify-instance-01.png) 3. In the **Network** field, leave **Create one for me** unless you want an existing VPC. 4. Under **Network access**, expand **Inbound internet access** and click **Set up now**. This reserves a public IP and opens the ports Coolify needs: - **Inbound ports** — keep **SSH (22/TCP)**, **HTTP (80/TCP)**, and **HTTPS (443/TCP)** checked. - **Additional ports** — add `8000` (TCP). The Coolify dashboard runs on this port. - **Source CIDRs** — `0.0.0.0/0` to allow access from anywhere, or use **My IP** to restrict it to your address while you set things up. ![Network access section with Inbound internet access set up and port 8000 added](/docs/images/marketplace/deploying-a-coolify-instance-02.png) 5. Set the sliders in **Hardware Specifications** to fit your workload. A minimum of **2 vCPU / 2 GB memory / 50 GB root disk** is a sensible starting point for a single-server Coolify install. 6. In **Options**, choose a **Billing period** and check the **SSH keys** you want to attach so you can `ssh` into the VM later. ![Hardware Specifications and Options sections with SSH key selected](/docs/images/marketplace/deploying-a-coolify-instance-03.png) 7. Click **Create VM**. ## Save the VM password After the VM is created, the portal shows a **VM Password** dialog **once**. Click **Show** to reveal it and **Copy** it into a password manager before closing — it cannot be retrieved later. ![VM Password dialog warning that the password is shown only once](/docs/images/marketplace/deploying-a-coolify-instance-04.png) Once the VM reaches the **READY** state, copy its **public IP** from the details page. ## Access Coolify Open the Coolify dashboard in a browser: ``` Coolify access: http://:8000/ ``` For example, if the VM's public IP is `203.0.113.42`, browse to `http://203.0.113.42:8000/`. The first time you visit the dashboard, register a user account and sign in. ### Welcome screen Coolify walks you through a short onboarding. On the **Welcome to Coolify** screen, click **Let's go!**. ![Welcome to Coolify onboarding screen](/docs/images/marketplace/deploying-a-coolify-instance-05.png) ### Choose a server type On **Step 1 — Server**, pick **This Machine** (Quick Start). This deploys directly on the Coolify VM you just created and skips the SSH key exchange you'd need for a remote server. ![Coolify Choose Server Type with This Machine selected](/docs/images/marketplace/deploying-a-coolify-instance-06.png) > **Tip:** If you'd rather run Coolify here and deploy workloads to another machine, pick **Remote Server** instead and follow Coolify's prompts to add its public key to that server's `~/.ssh/authorized_keys`. ### Finish setup On **Step 3 — Complete**, Coolify confirms the server, project, and Docker engine are ready. Click **Deploy Your First Resource** to start creating apps, or **Go to Dashboard**. ![Coolify Setup Complete screen with What's Configured summary](/docs/images/marketplace/deploying-a-coolify-instance-07.png) ## Next steps - See the [Coolify docs](https://coolify.io/docs/) for application templates, environment management, backups, and resource limits. - For ongoing VM management (Power, Scale, Reinstall), see [Cloud Compute](/docs/cloud-compute/cloud-compute). - To attach a custom domain, see [DNS management](/docs/dns/dns-management). ## GitLab ![](/docs/images/marketplace/gitlab-01.jpg) GitLab is a web-based platform that provides a complete DevOps lifecycle management tool. It offers features for version control, continuous integration, continuous delivery, and container orchestration. GitLab allows teams to collaborate on software development projects, manage repositories using Git, track issues, and automate the software delivery process. It integrates source code repositories, CI/CD pipelines, code review, and project management in a single interface. With built-in collaboration tools and a wide range of integrations, GitLab enables efficient and streamlined development workflows for teams of all sizes. ## System requirements It is recommended to utilize a server size of 4 CPU/8 GB RAM. ## Install GitLab 1. Login to the Web Portal with a valid American Cloud account 2. On the left navigation column choose 'Cloud Compute' 3. Click on "Create an Instance" select your "Project" and click "Proceed" 4. Select your location and network. Under "Choose Server Image" select "Marketplace Apps" tab and choose preferred "GitLab CE version" along with the desired "operating system" ![](/docs/images/marketplace/gitlab-02.png) ![](/docs/images/marketplace/gitlab-03.jpg) Fill out an email to be used for Let's Encrypt Certs and the domain name without `http/https` and `www.` ![](/docs/images/marketplace/gitlab-04.png) 5. After setting your environment variables, choose a server size and then click on "Add a new startup script". This will apply the environment variables you set earlier, so no further action is needed. ![](/docs/images/marketplace/gitlab-05.png) ![](/docs/images/marketplace/gitlab-06.png) 6. Click on Review and Deploy once reviewed click on Deploy Now. 7. Once the GitLab VM is deploying a DNS record can be added. The Public IP can be found under the Overview of the VM. ![](/docs/images/marketplace/gitlab-07.png) > Note: DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues > > **Example**: American Cloud DNS Management, **insert your GitLab instance public IP instead of 0.0.0.0** ![](/docs/images/marketplace/gitlab-08.png) > After your domain is resolving to the correct IP address and when the script completes, your GitLab installation will be ready. This usually takes 10-15 minutes from the time you add your A records but this can vary drastically depening on your DNS provider, in a worst case scenario we have seen DNS providers take up to 24 hours before the new A records are reflected on the internet. 8. SSH into the VM and run the following command to set the username/password for login ``` sudo gitlab-rake "gitlab:password:reset" ``` 9. Provide username `root` and select the desired password for the root account. ![](/docs/images/marketplace/gitlab-09.png) **Note:** The password must be at least 8 characters long and must not contain commonly used word or letter combinations. 10. Finally, use the username `root` and the previously established password to sign into GitLab ![](/docs/images/marketplace/gitlab-10.png) ## Troubleshooting * Webpage or certs not configured correctly. Likely due to DNS service lag. A reconfigure command can resolve this issue. 1. SSH into the VM 2. Run command ``` sudo gitlab-ctl reconfigure ``` * Use Gitlab-ctl to list the handlers by running ``` sudo gitlab-ctl status ``` * To restart all handlers use the command ``` sudo gitlab-ctl restart ``` or restart a specifice handler ``` sudo gitlab-ctl restart {handler} ``` "For additional information on GitLab maintenance commands, [Click here](https://docs.gitlab.com/omnibus/maintenance/)" ## Jitsi Meet ## 1. Set up your Jitsi Meet installation After choosing your Zone, Network, click on the Marketplace Apps tab, select Jitsi Meet and pick your desired version. A section for Environment Variables will be displayed. Fill in the following information. ![](/docs/images/marketplace/jitsi-meet-01.jpg) ![](/docs/images/marketplace/jitsi-meet-02.jpg) **Your Email** - This is the email address that will receive any LetsEncrypt certificate alerts. **Your Domain** - This is the domain you want to use for your Jitsi Meet instance, we will configure the A records later since we don't know what the public IP will be just yet. - Note: Only input your subdomain or root domain. Do not include "https" or "www". Just "**my-subdomain.rootdomain.com**" ## 2. Initialize your Jitsi Meet After setting your environment variables, choose a server size and then click on "Add a new startup script". This will apply the environment variables you set earlier, so no further action is needed. ![](/docs/images/marketplace/jitsi-meet-03.jpg) Click "Add startup script" to confirm. ![](/docs/images/marketplace/jitsi-meet-04.jpg) Verify that the values for **\{Your Email\}** and **\{Your Domain\}** are correctly entered in the Add New Startup Script configuration. (Optional) Apply any ssh keys you wish to use, and name your instance. Review, and deploy. ## 3. Configure DNS After your server has been created, note the public IP address on the instance overview page, then navigate to your DNS provider for **`your_domain`** and create A records for your domain. Create one mapping for your domain/subdomain, and one prefixed with "www.", as seen in the example below. (use your VM's public IP as the value instead of 0.0.0.0) ![](/docs/images/marketplace/jitsi-meet-05.png) - Note: DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues ## 4. Verify Jitsi deployment SSH into the server using the Username, Public IP Address, and Password provided during instance creation. After logging into the Virtual Machine, run the following command `tail -f /var/log/cloud-init-output.log` to monitor the installation status and confirm when DNS validation and installation are completed ![](/docs/images/marketplace/jitsi-meet-06.jpg) If the output displays **"Jitsi stack started"**, it confirms that the deployment completed successfully and DNS is configured correctly. ## 5. Config user To add authentication/admin user(s), please run the following command and add the `` and `` ![](/docs/images/marketplace/jitsi-meet-07.jpg) ## 6. Check your site Access the Jitsi web console using **\{Your Domain\}** configured during deployment. Users can create meeting rooms after accessing the site. Administrator privileges may require a one-time authentication using the configured `` and `` credentials. --- ## Troubleshooting If your Jitsi Meet installation is having issues, you can inspect the logs by connecting to the system with ssh and using docker-compose. ``` # View logs for all containers cd ~/docker-jitsi-meet-stable-10710 && docker compose -p jitsi-meet logs -f # Optional: View logs for specific containers docker compose -p jitsi-meet logs -f web docker compose -p jitsi-meet logs -f jicofo docker compose -p jitsi-meet logs -f jvb docker compose -p jitsi-meet logs -f prosody ``` If you are having trouble with your domain, or certificates/ssl, try restarting the proxy service. ``` cd ~/docker-jitsi-meet-stable-10710 && docker compose -p jitsi-meet restart web ``` ## Matomo Matomo is an open‑source web analytics platform and a privacy‑focused alternative to Google Analytics. In simple terms, it helps you understand who is visiting your website and how they interact with it—while ensuring that you retain full ownership of your data. ## What Matomo offers Matomo allows you to monitor and analyze key metrics such as: - Total number of visitors - Page views and most‑visited pages - Traffic sources (search engines, social media, direct access, etc.) - Visitor behavior, including clicks, downloads, and form submissions - Goals and conversion tracking ## Deploying instance with Matomo 1. Open your browser and navigate to [https://app.americancloud.com](https://app.americancloud.com) and navigate to 'Cloud Compute' ![](/docs/images/marketplace/matomo-01.jpg) 2. Click "CREATE AN INSTANCE" ![](/docs/images/marketplace/matomo-02.jpg) 3. Choose the appropriate project and click "Proceed." ![](/docs/images/marketplace/matomo-03.jpg) 4. Select the required zone where the instance will be created and choose the server type ![](/docs/images/marketplace/matomo-04.png) 5. Open the Marketplace Apps tab and select "Matomo." 6. Enter the required variables as prompted. ![](/docs/images/marketplace/matomo-05.png) **Important Note**: Do not create an A record in DNS before deploying the instance. Keep the domain name ready and once the instance is successfully created, use the public IP address to create the A record. This helps ensure an error‑free installation. 7. Configure the server with the desired specifications, Add the Startup Script. ![](/docs/images/marketplace/matomo-06.png) 8. Verify that the values entered earlier in the variables section are correctly reflected in the startup script popup. ![](/docs/images/marketplace/matomo-07.png) 9. After clicking "Add Startup Script," ensure the script is visible in the dashboard. Select the required SSH key and click "Deploy Now" to create the instance. ![](/docs/images/marketplace/matomo-08.png) 10. When the "Instance Starting" page appears, use the public IP address to create the DNS A record for the domain specified in the variables or startup scripts. ![](/docs/images/marketplace/matomo-09.png) **Matomo installation** 11. Once the instance is created, open a browser and navigate to the configured domain to begin the Matomo installation. Click "Next" to proceed. ![](/docs/images/marketplace/matomo-10.png) 12. During the system check, ensure that all checks show green ticks. This confirms the environment is correctly configured. Click "Next." ![](/docs/images/marketplace/matomo-11.png) 13. For the database setup, log in to the instance using the SSH key or password. Run the command **`docker ps -a`** to list the database and container names or IDs. ![](/docs/images/marketplace/matomo-12.png) 14. Use the command **`cat /matomo/.env`** to retrieve the database username and password. ![](/docs/images/marketplace/matomo-13.png) 15. Enter the database name, username, and password obtained from the previous step into the database setup page, then click "Next." ![](/docs/images/marketplace/matomo-14.png) 16. The installer will create the required database tables and prompt for confirmation. Click "Next" to continue. ![](/docs/images/marketplace/matomo-15.png) **User configuration and final setup** 17. For the Superuser setup, use the same username and password defined in the startup script. Click "Next." ![](/docs/images/marketplace/matomo-16.png) 18. Configure a website for tracking and click "Next." ![](/docs/images/marketplace/matomo-17.png) 19. The tracking code required for website analytics will be displayed. You may scroll down and click "Next." This tracking code will also be available again after the setup is complete. ![](/docs/images/marketplace/matomo-18.png) **Completion** 20. A confirmation screen will appear indicating that Matomo has been successfully installed. Click "Continue to Matomo" to access the dashboard. ![](/docs/images/marketplace/matomo-19.png) 21. Log in using the Superuser credentials created earlier. ![](/docs/images/marketplace/matomo-20.png) 22. After logging in, the tracking code will be shown again. Choose the preferred method to add this script to your website for analytics tracking. ![](/docs/images/marketplace/matomo-21.png) 23. To add additional websites, click on "All Websites" in the top‑right corner of the dashboard. ![](/docs/images/marketplace/matomo-22.png) ## NextCloud AIO Build ## Build Instance 1. Login to the Web Portal with a valid American Cloud account. 2. On the left navigation column choose 'Cloud Compute'. 3. Click on "Create an Instance" select your "Project" and click "Proceed" 4. Select your location and network. Under "Choose Server Image" select "Marketplace Apps" tab and choose "Nextcloud AIO" ![](/docs/images/marketplace/nextcloud-01.png) ![](/docs/images/marketplace/nextcloud-02.png) 5. Choose a server size and then click "Add a new startup script". ![](/docs/images/marketplace/nextcloud-03.png) ![](/docs/images/marketplace/nextcloud-04.png) 6. Select "ADD STARTUP SCRIPT" in the popup. This will run the initial command to build Nextcloud AIO. ![](/docs/images/marketplace/nextcloud-05.png) 7. Click "Review and Deploy" then "Deploy Now". 8. While the machine is deploying create the DNS A-record using the Public IP. ![](/docs/images/marketplace/nextcloud-06.png) **Note:** DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues **Example** American Cloud DNS Management, insert your Nextcloud instance Public IP instead of 0.0.0.0 ![](/docs/images/marketplace/nextcloud-07.png) 9. Once the VM build is complete open a browser and navigate to https://public_ip:8080. Be sure to annotate the password on this page before proceeding. ![](/docs/images/marketplace/nextcloud-08.png) For further nextcloud documentation [Click Here](https://nextcloud.com/blog/how-to-install-the-nextcloud-all-in-one-on-linux/) ## Troubleshooting Nextcloud - Containers not starting 1. If containers fail to start following nextcloud launch use the reload option. ![](/docs/images/marketplace/nextcloud-09.png) 2. The containers will reload and show as running. If containers remain as starting, stop and restart containers using the "Stop Containers" function. ![](/docs/images/marketplace/nextcloud-10.png) 3. Using one or both of the above techniques the containers should show as running. ## Supabase After choosing your Zone, Network, click on the Marketplace Apps tab, select Supabase and pick your desired version. A section for Environment Variables will be displayed. Fill in the following information. ![](/docs/images/marketplace/supabase-01.png) ## Your Email - This is the email address that will receive any LetsEncrypt certificate alerts. ## Your Domain - This is the domain you want to use for your Supabase instance, we will configure the A records later since we don't know what the public IP will be just yet. - Note: Only input your subdomain or root domain. Do not include "https" or "www". Just "[my-subdomain.rootdomain.com](http://my-subdomain.rootdomain.com/)" ## JWT - [Go here](https://supabase.com/docs/guides/self-hosting/docker#generate-api-keys) to find a new JWT token. Use it to generate an `ANON_KEY` and a `SERVICE_KEY` from it while you're there and paste into the following 2 settings. - *If you don't want to use the key generated by the site, you can create your own with `openssl rand 48 | base64` and use that on that page to generate ANON and SERVICE keys.* ## ANON_KEY - The `ANON_KEY` from the **JWT** step above. ## SERVICE_KEY - The `SERVICE_KEY` from the **JWT** step above. ## BASIC_AUTH_USER - The username you want to use to access Supabase in your browser. ## BASIC_AUTH_PASSWORD - The password you want to use to access Supabase in your browser. ## 2. Initialize your Supabase After setting your environment variables, choose a server size and then click on "Add a new startup script". This will apply the environment variables you set earlier, so no further action is needed. ![](/docs/images/marketplace/supabase-02.png) Click "Add startup script" to confirm. (Optional) Apply any ssh keys you wish to use, and name your instance. Review, and deploy. ## 3. Configure DNS After your server has been created, note the public IP address on the instance overview page, then navigate to your DNS provider for `your_domain` and create A records for your domain. Create one mapping for your domain/subdomain, and one prefixed with "www.", as seen in the example below. (use your VM's public IP as the value instead of 0.0.0.0) ![](/docs/images/marketplace/supabase-03.png) - Note: DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues ## 4. (Optional) Restart Proxy The last step is to tell your server to get new certificates, now that DNS is configured. This step might not be necessary if you configured your A records quickly, since the proxy container usually takes a minute or two to finish starting. SSH into your server, using the Username, IP address, and Password provided to you. - Note: Use your Public IP instead of 0.0.0.0 ``` ssh cloud@0.0.0.0 ``` Once you are in the VM, run the following command to restart your nginx proxy: ``` cd ~/nginx && docker compose restart nginx ``` ## 5. Check your site Congratulations! Your Supabase will be available shortly at the domain you configured earlier. Just be aware that the proxy can take a few minute to initialize and apply certificates, so try waiting 2 minutes or so before inspecting the VM. ## Troubleshooting If your Supabase installation is having issues, you can inspect the logs by connecting to the system with ssh and using docker compose. ``` cd ~/supabase/docker && docker compose logs -f ``` ``` cd ~/nginx && docker compose logs -f ``` If you are having trouble with your domain, or certificates/ssl, try restarting the proxy service. ``` cd ~/nginx && docker compose restart nginx ``` If you are stuck on the page that says "Connecting to Default Project", you may wish to recreate your database. ![](/docs/images/marketplace/supabase-04.png) To recreate your database, run the following commands to recreate your database: ``` cd ~/supabase/docker docker compose down sudo rm -rf volumes/db/data/ docker compose up -d ``` ## Wordpress on Open Lite Speed ![](/docs/images/marketplace/wordpress-on-open-lite-speed-01.png) ## OpenLite Speed LiteSpeed is a high-performance web server known for its speed and efficiency. Utilizing an event-driven architecture, it outpaces traditional servers like Apache, handling numerous connections with minimal resource usage. With advanced caching and support for protocols like HTTP/3, LiteSpeed significantly accelerates website loading times. Its built-in security features, including a Web Application Firewall (WAF), defend against online threats. LiteSpeed is a popular choice for high-traffic websites, offering optimal performance, scalability, and user-friendly configuration interfaces for seamless integration and management, making it a preferred solution for businesses and developers aiming to deliver fast, secure, and responsive web experiences. ## Create Instance 1. Login to the Web Portal with a valid American Cloud account. 2. On the left navigation column choose 'Cloud Compute'. 3. Click on "Create an Instance" select your "Project" and click "Proceed" 4. Select your location and network. Under "Choose Server Image" select "Marketplace Apps" tab and choose "WordPress" ![](/docs/images/marketplace/wordpress-on-open-lite-speed-02.png) ![](/docs/images/marketplace/wordpress-on-open-lite-speed-03.png) 5. Choose a server size. ![](/docs/images/marketplace/wordpress-on-open-lite-speed-04.png) 6. ***Optional*** Generate or add SSH key. Click on Review and Deploy once reviewed click on Deploy Now. 7. ***Optional*** While the Wordpress VM is deploying a DNS record can be added if you already know what domain you are going to use for your site. The Public IP can be found under the Overview of the VM. ![](/docs/images/marketplace/wordpress-on-open-lite-speed-05.png) **Note:** DNS providers have different methods of doing this, please contact your DNS provider if you are having any issues If desired American Cloud offers complimentary DNS Management. Add your domain to the DNS Management section in the left navigation menu on American Cloud. Afterwards go to your registar's website and point your domain to the American Cloud nameservers: [ns1.americancloud.org](http://ns1.americancloud.org/) and [ns2.americancloud.org](http://ns2.americancloud.org/). Inside the American Cloud UI navigate to the DNS Manager and create the appropriate A records. **Example Below:** Inside American Cloud DNS Management click the edit pencil for your new domain and create the appropriate A records, remember to swap 0.0.0.0 for your new Public IP address. ![](/docs/images/marketplace/wordpress-on-open-lite-speed-06.png) 8. Navigating to the Public IP Address via a browser will display the OpenLiteSpeed landing page. Select the Quickstart Guide link to open LiteSpeed docs if desired. ![](/docs/images/marketplace/wordpress-on-open-lite-speed-07.png) - [OpenLiteSpeed Quickstart Guide](https://docs.litespeedtech.com/cloud/images/wordpress/) 9. As directed on the LiteSpeed landing page SSH into the Wordpress instance utilizing the public ip, username, and password found on the instance overview page. ## Configure Litespeed ### Installed Software ![](/docs/images/marketplace/wordpress-on-open-lite-speed-08.png) 1. SSH into the instance ``` ssh cloud@public_ip ``` For further information on Using SSH [Click Here](https://docs.americancloud.com/hc/docs/articles/1722537850-managing-ssh-keys). 2. Insert Domain ``` Your domain: YOUR_DOMAIN.com ``` 3. Confirm Domain Name ``` The domain you put is: YOUR_DOMAIN.com Please verify it is correct. [y/N] y ``` 4. Determine if let's encrypt is ideal for the sites certificate and select y/n ``` Do you wish to issue a Let's encrypt certificate for this domain [y/N] ``` 5. Enter and confirm the email for the certificate ``` Please enter your E-mail: YourEmail@domain.com The E-mail you entered is: YourEmail@domain.com Please verify it is correct: [y/N] ``` **Note:** Once email is confirmed a key cert will be created. The read-out identify the location of the cert and logs. If a failure occurs at this point, check DNS to ensure A records have been updated. 6. Determine to force HTTPS rules be applied ``` Do you wish to force HTTPS rewrite rule for this domain? [y/N] ``` 7. Next determine whether or not to update the system ``` Do you wish to update the system now? This will update the web server as well. [Y/n]? ``` 8. Once the update is complete the site will be running at the domain specified. Open a browser and navigate to the site. Here the initial landing page for wordpress with be displayed ## Environment Differences - `cloud` is the default user for inital setup VM's in the American Cloud environment. The DB and panel passwords are stored in the root directory. Follow the below steps to access these passwords. 1. Access root utilizing `sudo -i` or preferred method. 2. Use the command `cat .db_password` which will present the MySQL root and wordpress passwords. 3. Use the command `cat .litespeed_password` to retrieve the panel password. --- # WordPress Managed WordPress hosting and site management ## Enterprise WordPress plans For WordPress Reseller and Enterprise plans, pricing and resources are tailored to your specific needs. These plans are designed for agencies, developers, and organizations that require greater flexibility, higher capacity, and custom performance or security requirements beyond standard packages. Customized plans include the same core benefits—high-performance WordPress acceleration, Redis object caching, SSL/TLS, automated backups, staging and cloning, SSH access, advanced DNS control, and proactive monitoring—while allowing adjustments to storage, bandwidth, account limits, and resource allocations. To discuss pricing, feature customization, or enterprise-level requirements, please [contact our team](/contact-us). We'll work with you to design a WordPress hosting solution that aligns with your technical goals and business growth. ## WordPress hosting American Cloud's managed WordPress hosting handles provisioning, performance, security, and backups so you can focus on your site. Sites run with Redis object caching, AccelerateWP, SSL/TLS by default, automated backups, staging and cloning, and proactive monitoring. This article covers the full lifecycle: creating a site, attaching a custom domain, managing your instance, changing plans, and adding more sites. ## Create a WordPress instance 1. In the left navigation, under **Applications**, select **WordPress**. 2. In the top right of the WordPress page, click **+ Create WordPress**. ![WordPress page in the portal with the Create WordPress button](/docs/images/wordpress/wordpress-hosting-01.png) 3. On the **Create WordPress** page, choose a **Plan**: - **WordPress 10** — 10 GB disk, 20 GB bandwidth, 1 site, 10,000 visits/mo. - **WordPress 25** — 50 GB disk, 100 GB bandwidth, 3 sites, 50,000 visits/mo. For larger or customized plans, see [Enterprise WordPress plans](/docs/wordpress/enterprise-plans). ![Create WordPress page showing the Plan selector and Configuration section](/docs/images/wordpress/wordpress-hosting-02.png) 4. In the **Configuration** section, optionally enter a **Custom domain** (for example, `my.testdomain.com`). Leave it blank to use a temporary `*.wpsquared.site` domain — you can attach a custom domain later. 5. Review the cost estimate (monthly, hourly, prorated amount charged today) on the right, then click **Create WordPress**. ![Create WordPress page with a plan selected, custom domain entered, and cost estimate panel](/docs/images/wordpress/wordpress-hosting-03.png) The new instance appears in the Instances list with status **PROVISIONING**. ![Instances list showing a new instance with status PROVISIONING](/docs/images/wordpress/wordpress-hosting-04.png) Once status is **READY**, click **View** to open the instance. ![Instances list showing the instance with status READY and View action](/docs/images/wordpress/wordpress-hosting-05.png) ## Manage your instance The instance detail page shows everything you need to manage the hosting and its sites. ![WordPress instance detail page with Manage, Change Plan, and Cancel actions, and panels for Instance, Websites, Resource Usage, Nameservers, Quota, and Account Management](/docs/images/wordpress/wordpress-hosting-06.png) - **Instance** — username, package, monthly rate, creation date. - **Websites** — every site on this instance with its domain, name, WP version, theme, DB and files size. - **Resource Usage** — bandwidth consumed against the plan's allowance. - **Nameservers** — the DNS servers to point your custom domain at (see [Attach a custom domain](#attach-a-custom-domain)). - **Quota** — per-resource limits for this plan. - **Account Management** — update the WordPress admin password. Top-right actions: - **Manage** — open the in-browser site management tools. - **Change Plan** — upgrade or change to a different plan. - **Cancel** — cancel and remove the instance. ## Attach a custom domain When you create an instance without a custom domain, the site is reachable at a temporary `*.wpsquared.site` address shown in the **Websites** table. ![Websites table showing a temporary wpsquared.site domain](/docs/images/wordpress/wordpress-hosting-07.png) To use your own domain: 1. Open the instance detail page and copy the values from the **Nameservers** panel. They look like `ns1.wp2rsdc0-0.americancloud.com` and `ns2.wp2rsdc0-1.americancloud.com` (the exact subdomains depend on your region). 2. Log in to your domain registrar and point the domain's nameservers at those values. American Cloud will automatically create the A and CNAME records for your site. 3. Alternatively, keep your existing DNS provider (for example, Cloudflare) and create: ``` example.com A 45.39.56.5 www.example.com CNAME example.com ``` Propagation usually completes within a few minutes. ## Change plan To move to a larger plan (for example, to host more sites or get more bandwidth): 1. On the instance detail page, click **Change Plan** in the top right. 2. Select the new plan and confirm. The instance is re-provisioned to the new plan; existing sites and data are preserved. ## Add another site Multi-site plans (WordPress 25 and Enterprise) support multiple sites per instance. 1. Open the instance and click **Manage** in the top right. 2. In the management interface, choose **Create New Site**. 3. Either pick a domain now or use a temporary domain and add a custom one later. The new site appears in the **Websites** table once provisioning completes. If you've hit your plan's site limit, [change plan](#change-plan) first. ## Update the WordPress admin password On the instance detail page, scroll to **Account Management**, enter a new password (minimum 8 characters), and click **Update Password**. ## Migrations and support - See [WordPress migrations](/docs/wordpress/migrations) for moving an existing site to American Cloud. - For help, contact us at [americancloud.com/contact-us](https://americancloud.com/contact-us). ## WordPress migrations We offer complimentary WordPress migrations to make your move to American Cloud simple and risk-free. Our team handles the transfer of your site, databases, and core configurations with minimal downtime, ensuring your site is ready to perform on our platform. No hidden fees, no disruption—just a smooth transition. Should you want to perform the migration, you can do so with the all-in-one WordPress migration plugin. You would install the All-in-One WordPress Migration plugin on their existing site, generate a full site export, and upload it to your new American Cloud WordPress environment. Once imported, the site is verified, caching and performance features are enabled, and SSL is applied—ensuring the site is live, secure, and optimized with minimal downtime. For more information, please review: [https://wordpress.org/plugins/all-in-one-wp-migration/](https://wordpress.org/plugins/all-in-one-wp-migration/) Please feel free to reach out to us for complimentary migrations: [https://americancloud.com/contact-us](https://americancloud.com/contact-us) --- # Tutorials Step-by-step guides and how-tos ## Cockpit Installation Cockpit is a tool for server administration that provides you with real-time information about your server's status. It displays data on CPU usage, filesystem statistics, processes, and other relevant details. One of the advantages of using Cockpit is that it does not consume any server resources until you log in to the control panel. The service is only activated when you access the control panel. Cockpit enables you to perform various server administration tasks, such as managing users and addressing network issues. It also allows you to access a terminal from your computer or phone's browser. To log in and manage the system, Cockpit utilizes your system's users and sudo for privilege escalation. As a result, it does not introduce an additional layer of security considerations by creating a separate set of Cockpit-only users for your server. ## Instructions Using the below guides you can install Cockpit on various different Linux OS's. ### Ubuntu Ubuntu 17.04 and later: 1. Install cockpit: `. /etc/os-release` `sudo apt install -t ${VERSION_CODENAME}-backports cockpit` 2. Enable cockpit: `sudo systemctl enable --now cockpit.socket` ### Fedora 1. Install cockpit: `sudo dnf install cockpit` 2. Enable cockpit: `sudo systemctl enable --now cockpit.socket` 3. Ensure that the firewall is open: `sudo firewall-cmd --add-service=cockpit` `sudo firewall-cmd --add-service=cockpit --permanent` ### CentOS CentOS 7 and later: 1. Install cockpit: `sudo yum install cockpit` 2. Enable cockpit: `sudo systemctl enable --now cockpit.socket` 3. Open the firewall: `sudo firewall-cmd --permanent --zone=public --add-service=cockpit` `sudo firewall-cmd --reload` ### Debian Debian 10 and later: 1. To get the latest version, we recommend to enable the backports repository (as root): `. /etc/os-release` `echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" > \` `/etc/apt/sources.list.d/backports.list` `apt update` 2. Install or update the package: `apt install -t ${VERSION_CODENAME}-backports cockpit` ### Rocky Linux Rocky Linux 8 and later: 1. Install cockpit `sudo yum install cockpit` 2. Enable cockpit: `sudo systemctl enable --now cockpit.socket` 3. Allow port through firewall: `sudo firewall-cmd --add-service=cockpit --permanent` `sudo firewall-cmd --reload` ## Connecting JuiceFS to American Cloud A2 object storage This tutorial walks through using American Cloud's A2 object storage as the backing store for a [JuiceFS](https://juicefs.com) filesystem. You'll create an A2 storage unit and bucket, grab the S3 credentials, and point JuiceFS at them. For full A2 portal documentation, see [A2 object storage](/docs/object-storage/a2-object-storage). ## Create an A2 storage unit 1. Log in to the American Cloud portal. 2. In the left navigation, under **Storage**, select **Object storage**. 3. In the top right, click **+ Create Unit**. ![Object storage page with the Create Unit button](/docs/images/tutorials/connecting-juice-fs-to-american-cloud-a2-object-01.png) 4. On the **Create object storage** page, enter a **Name** (alphanumeric characters only) and click **Create Storage Unit**. ![Create object storage form](/docs/images/tutorials/connecting-juice-fs-to-american-cloud-a2-object-02.png) ## Get S3 credentials Click the new unit in the storage units list to open its detail page. The **S3 Access** panel shows the values JuiceFS needs: - **Endpoint** — `a2-west.americancloud.com` - **Access key** — click **[copy]**. - **Secret key** — click **[show]**, then **[copy]**. ![Storage unit detail page with the S3 Access panel](/docs/images/tutorials/connecting-juice-fs-to-american-cloud-a2-object-03.png) ## Create a bucket 1. On the storage unit detail page, in the **Buckets** section, click **+ Add Bucket**. 2. Enter a **Bucket name** (lowercase letters, numbers, dots, and hyphens) and click **Create Bucket**. ![Create Bucket dialog](/docs/images/tutorials/connecting-juice-fs-to-american-cloud-a2-object-04.png) 3. The bucket appears in the list with its full S3 URL — copy this; you'll pass it to JuiceFS as the `--bucket` value. ![Bucket list showing the new bucket and its S3 URL](/docs/images/tutorials/connecting-juice-fs-to-american-cloud-a2-object-05.png) ## Format the JuiceFS filesystem From your JuiceFS machine, format a new filesystem backed by the A2 bucket. Replace the placeholders with the values you just gathered: ```bash juicefs format \ --storage s3 \ --bucket https://a2-west.americancloud.com// \ --access-key \ --secret-key \ redis://localhost:6379/1 \ myjfs ``` - `--bucket` is the bucket's S3 URL from the previous step. - The final two arguments are the metadata engine URL (`redis://…` in this example; PostgreSQL, MySQL, and SQLite are also supported) and a name for the filesystem. > **Note:** Older JuiceFS versions use `juicefs create --backend s3 --bucket --endpoint ` instead of `juicefs format --storage s3 --bucket `. The example above uses the current syntax. ## Mount the filesystem ```bash sudo juicefs mount myjfs /mnt/jfs ``` Replace `myjfs` with the name you used in the `format` command and `/mnt/jfs` with where you want the filesystem mounted on your machine. ## Share over the network To use the JuiceFS mount as a shared file system, re-export the mount point via NFS, SMB, or any other network filesystem protocol on the host. ## Deploy a simple web app with Kamal This tutorial walks through provisioning a virtual machine on American Cloud and using [Kamal](https://kamal-deploy.org) to deploy a simple Dockerized web app to it. > **Alert:** Kamal connects to the target host as `root`. Only enable root SSH on hosts where you fully understand the security implications. ## Create a VM For full VM portal documentation, see [Cloud Compute](/docs/cloud-compute/cloud-compute). 1.) In the left navigation, under **Compute**, select **Virtual machines**, then click **+ Create VM** in the top right. ![Virtual machines list with the Create VM button](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-01.png) 2.) On the **Create virtual machine** page, fill in **Configuration**: - **VM name** — lowercase letters, numbers, and hyphens (for example, `kamal-host`). - **Region** — for example, **US Central**. - **Package type** — for example, **Standard Custom**. - **Deploy from** — **Operating system**. - **Operating system** — a Linux image (for example, **Ubuntu 26.04 LTS**). - **Network** — **Create one for me** unless you have an existing VPC. ![Create VM Configuration section](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-02.png) 3.) Set the sliders in **Hardware Specifications** (CPU, Memory, Root disk) to fit your app. 4.) In **Options**: - **SSH keys** — check the box next to the key you want Kamal to use. (Add a key first under **Account → SSH keys** if you don't have one. See [Managing SSH keys](/docs/cloud-compute/managing-ssh-keys).) - **User data / cloud-init** *(optional)* — if your image doesn't permit root SSH by default, paste the snippet below. Replace `mypubkey` with the same public key you attached above. ```bash #!/bin/bash echo "PermitRootLogin yes" >> /etc/ssh/sshd_config SSH_KEY_CONTENT="mypubkey" echo "$SSH_KEY_CONTENT" >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys chown root:root /root/.ssh/authorized_keys systemctl restart sshd ``` ![Create VM Options section with SSH keys and User data fields](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-03.png) 5.) Click **Create VM**. Once the VM is **READY**, copy its public IP from the details page. ## Confirm root SSH Test that you can reach the VM as root: ```bash ssh root@ ``` If it fails, recreate the VM with the cloud-init script from step 4. ## Install Kamal 6.) Now that root ssh access is established on the VM. It's time to install Kamal. There are a couple of prerequisites prior. - Docker and buildx is required on your machine. This tutorial is built on Mac so `brew install docker` and `brew install docker-buildx` was utilized. If docker and buildx is not installed a failure will occur during `kamal setup`. This step may be different depending on OS. It a relatively quick lookup. - The private key matching the public one on your VM should be added to your ssh-agent, you can ensure this is the case by running `ssh-add ~/.ssh/kamal_privkey` (whatever your key is) 7.) Install Kamal locally by running `gem install kamal` or set up an alias to [run in docker.](https://kamal-deploy.org/docs/installation/dockerized/) - If issues arise in step 7, you'll probably need to update ruby and set the ruby environment. 8.) Choose your container registry (it can be public or private), and create a personal access token with `write:packages` scope in order to push images to it. We are going to use [ghcr.io](http://ghcr.io/) and a private registry for this example. 9.) Select user menu in top right corner. ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-13.jpeg) 10.) Select "Settings" ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-14.jpeg) 11.) Scroll to the bottom of the menu and select "Developer settings" ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-15.jpeg) 12.) In the next menu select "Personal access tokens". Then in the dropdown select "Tokens (classic)" ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-16.jpeg) 13.) Select "Generate New Token" followed by "Generate new token (classic)" from the dropdown. ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-17.jpeg) 14.) In the section provide a name for the token and at a minimum select "write:packages" ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-18.jpeg) 15.) Select "Generate token" ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-19.jpeg) 16.) Copy the key to be utilized in the next steps. ![](/docs/images/tutorials/deploy-a-simple-web-app-with-kamal-20.jpeg) 17.) Set your personal access token as `KAMAL_REGISTRY_PASSWORD` using the export command below: ``` export KAMAL_REGISTRY_PASSWORD=ghp_12345abcde ``` 18.) Create a directory for kamal in the location you'd like to run it. For my example I'm simply creating on my `~/Desktop` utilizing `mkdir kamal` 19.) Set up your code, if you haven't already. Make sure you include a `Dockerfile` and that your app returns a `200 ok` on the path `/up` To test we can use some sample code. Inside the kamal directory create two files `Dockerfile` and `server.ts` 20.) server.ts ``` const server = Deno.listen({ port: 80 }); console.log("Server running on http://localhost:80"); for await (const conn of server) { handleConnection(conn); } async function handleConnection(conn: Deno.Conn) { for await (const requestEvent of Deno.serveHttp(conn)) { const url = new URL(requestEvent.request.url); requestEvent.respondWith(new Response("Hello, Kamal!", { status: 200 })); } } ``` 21.) Dockerfile ``` FROM denoland/deno:latest WORKDIR /app COPY server.ts . EXPOSE 80 CMD ["deno", "run", "--allow-net", "server.ts"] ``` ***22.) (Optional) Skip this step if you are already using git.*** If your code is not already committed with git, you can continue by simply using git locally by running these commands ``` git init git add . git commit -m "Initial commit" ``` 23.) Initialize kamal by running `kamal init` from the kamal directory. 24.) Update your newly created `config/deply.yml` file located in the kamal directory with the below code. Consult the [Kamal docs](https://kamal-deploy.org/docs/configuration/overview/) for more options. **Ensure to change line 4&13 to reflect the username of the repository. Line 8 will change to server Public IP.** ``` # Name of your application. Used to uniquely configure containers. service: kamal-demo # Name of the container image. image: github-username/kamal-demo # Deploy to these servers. servers: web: - 192.168.0.0 #<-- Put your VM's public IP here # Credentials for your image host. registry: # Specify the registry server, if you're not using Docker Hub server: ghcr.io username: github-username # Always use an access token rather than real password (pulled from .kamal/secrets). password: - KAMAL_REGISTRY_PASSWORD # Configure builder setup. Make sure you use this if you are building on a Mac. builder: arch: amd64 ``` This mapping should already be present but to double-check that your `.kamal/secrets` file includes this mapping run: `KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD` 25.) Commit your file changes to git - That's it! You're ready to deploy your app. 26.) Run `kamal setup` to begin the build on the host machine. 27.) Verify your app is running on your VM(s) by logging into your VM and checking the app `curl -X GET "http://localhost:80/"` This should return a `Hello, Kamal!` It's important before making your app public to utilize system hardening techniques as they're not installed by default. [Click here](https://rameerez.com/kamal-tutorial-how-to-deploy-a-postgresql-rails-app/) for a good article of reference. ## Deploying Web Applications with Kubernetes on American Cloud Kubernetes Service (ACKS) **Ensure No Other Proxies are Running on the local machine.** Deploying Web Applications with Kubernetes on American Cloud Kubernetes Service (ACKS) ## Prerequisites - Install `kubectl` by following [these instructions](https://kubernetes.io/docs/tasks/tools/#kubectl) - Install `helm` by following [these instructions](https://helm.sh/docs/intro/install/) - Owned domain with the ability to manage DNS - Dockerized application images in a public or private registry (extra steps in section [Connecting to Private Image Repositories](https://docs.americancloud.com/hc/docs/articles/1722539534-deploying-web-applications-with-kubernetes-on-american-cloud-kubernetes-service-acks)) ## 1. Provisioning Kubernetes Cluster 1. Choose a name, project, version, region, and node plan for your ACKS cluster. ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-01.png) ## 2. Connecting to Kubernetes Cluster 1. Once the cluster is in "Running" state: 2. Download the cluster config file by clicking on "Download Config File" ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-02.png) 3. Move the `kube.conf` file to a new directory. You'll be creating more files alongside it in order to set up your app. **Note**: `kube.conf` contains connection details on how your machine will connect and dispatch commands to the cluster. Every action will be of the form: `kubectl --kubeconfig kube.conf` unless you set it as the global kube config. - Set `kube.conf` as the default config by running `export KUBECONFIG=kube.conf`, or by copying the file to `~/.kube/config` **Note**: Example `1-create-admin-user.yaml` ``` apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard ``` *This generates one user (the ServiceAccount) and gives it the permissions necessary to access the Dashboard (the ClusterRoleBinding)* - Run `kubectl apply -f 1-create-admin-user.yaml` to create a user profile in order to generate access tokens to log in to the Dashboard. ``` ac-demo % kubectl apply -f 1-create-admin-user.yaml serviceaccount/admin-user created clusterrolebinding.rbac.authorization.k8s.io/admin-user created ``` 4. Run `kubectl proxy` in a new terminal to start the Dashboard UI locally. Leave this running in the background. 5. Open this url in your browser: [http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/) 6. Run `kubectl -n kubernetes-dashboard create token admin-user` to get a fresh token, and paste it in the input field of the Dashboard login. ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-03.png) 7. You will be met with an empty dashboard, and the namespace `default` selected. ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-04.png) ## 3. Creating App Resources First we want to get our app running in its own pods. Then we can expose it. We are going to create: **1 Deployment** (a prescriptive model of your application including environment variables, port mappings, and scaling details) **1 Service** (a way of allowing external access into your application) If your images are hosted in a private repository, you will need to create **1 Secret** as well (a protected resource containing repository access information, assuming your images are in a private registry) [Connecting to Private Image Repositories](https://docs.americancloud.com/hc/docs/articles/1722539534-deploying-web-applications-with-kubernetes-on-american-cloud-kubernetes-service-acks) Let's continue our example for now by pulling a public image which will run on internal port 8080. **Note**: Example `2-demo-app-deployment.yaml` ``` apiVersion: apps/v1 kind: Deployment metadata: name: demo-app namespace: default spec: replicas: 2 selector: matchLabels: app: demo-app strategy: type: RollingUpdate template: metadata: labels: app: demo-app spec: containers: - image: paulbouwer/hello-kubernetes:1.8 imagePullPolicy: IfNotPresent name: demo-app env: - name: MESSAGE value: Hello world! ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: demo-svc spec: type: ClusterIP ports: - port: 80 targetPort: 8080 selector: app: demo-app ``` Deploy by running `kubectl apply -f 2-demo-app-deployment.yaml` You can check on your resources by running `kubectl get pods` and `kubectl get svc`, or by checking in your Dashboard: ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-05.png) ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-06.png) Congratulations! Your application is running in Kubernetes. ## 4. Exposing Your App Next, we must create LoadBalancer and Ingress resources to allow external access. We start by installing the Kubernetes Nginx Ingress Controller ``` ac-demo % helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx "ingress-nginx" has been added to your repositories ``` ``` ac-demo % helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "ingress-nginx" chart repository Update Complete. ⎈Happy Helming!⎈ ``` ``` ac-demo % helm install nginx-ingress ingress-nginx/ingress-nginx --set controller.publishService.enabled=true NAME: nginx-ingress LAST DEPLOYED: Tue Oct 25 20:40:16 2022 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: The ingress-nginx controller has been installed. It may take a few minutes for the LoadBalancer IP to be available. You can watch the status by running 'kubectl --namespace default get services -o wide -w nginx-ingress-ingress-nginx-controller' An example Ingress that makes use of the controller: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example namespace: foo spec: ingressClassName: nginx rules: - host: www.example.com http: paths: - pathType: Prefix backend: service: name: exampleService port: number: 80 path: / # This section is only required if TLS is to be enabled for the Ingress tls: - hosts: - www.example.com secretName: example-tls If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided: apiVersion: v1 kind: Secret metadata: name: example-tls namespace: foo data: tls.crt: tls.key: type: kubernetes.io/tls ``` Take note of the new public ip after a couple minutes by running `kubectl --namespace default get services -o wide -w nginx-ingress-ingress-nginx-controller` Now we create an Ingress to point traffic to the LoadBalancer: **Note**: Example `3-nginx-ingress.yaml` ``` apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: kubernetes.io/ingress.class: nginx spec: rules: - host: "demo.your_domain_name" http: paths: - pathType: Prefix path: "/" backend: service: name: demo-svc port: number: 80 ``` Before we apply it, we need to ensure that we have a DNS A record pointing your domain to the new public ip of your LoadBalancer. Apply the Ingress: `kubectl apply -f 3-nginx-ingress.yaml` Go to https://demo.your_domain_name and see the Hello Kubernetes app! ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-07.png) ## 5. Securing Your App Now we need to get SSL / HTTPS playing nicely. ``` ac-demo % kubectl create namespace cert-manager namespace/cert-manager created ``` ``` ac-demo % helm repo add jetstack https://charts.jetstack.io "jetstack" has been added to your repositories ``` ``` ac-demo % helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "jetstack" chart repository ...Successfully got an update from the "ingress-nginx" chart repository Update Complete. ⎈Happy Helming!⎈ ``` ``` ac-demo % helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.6.0 --set installCRDs=true NAME: cert-manager LAST DEPLOYED: Tue Oct 25 21:05:28 2022 NAMESPACE: cert-manager STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: cert-manager v1.6.0 has been deployed successfully! In order to begin issuing certificates, you will need to set up a ClusterIssuer or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer). More information on the different types of issuers and how to configure them can be found in our documentation: https://cert-manager.io/docs/configuration/ For information on how to configure cert-manager to automatically provision Certificates for Ingress resources, take a look at the `ingress-shim` documentation: https://cert-manager.io/docs/usage/ingress/ ``` **Note**: Example `4-production-issuer.yaml` ``` apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: # Email address used for ACME registration email: your_email_address server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: # Name of a secret used to store the ACME account private key name: letsencrypt-prod-private-key # Add a single challenge solver, HTTP01 using nginx solvers: - http01: ingress: class: nginx ``` ``` ac-demo % kubectl apply -f 4-production-issuer.yaml clusterissuer.cert-manager.io/letsencrypt-prod created ``` Update the Ingress by using a new config file: **Note**: Example `5-nginx-ingress-secured.yaml` ``` apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - demo.your_domain secretName: demo-tls rules: - host: "demo.your_domain" http: paths: - pathType: Prefix path: "/" backend: service: name: demo-svc port: number: 80 ``` ``` ac-demo % kubectl apply -f 5-nginx-ingress-secured.yaml ingress.networking.k8s.io/demo-ingress configured ``` ## Connecting to Private Image Repositories In order to connect to a private image or package repository, a token with sufficient access to pull images needs to be encoded and stored in Kubernetes as a Secret. In this example, we will be connecting to a private registry (GHCR: GitHub Container Registry) which contains a Docker image with a NextJS web application. We create a new personal access token with scope `read:packages` by visiting [https://github.com/settings/tokens/new?scopes=read:packages](https://github.com/settings/tokens/new?scopes=read:packages) ![](/docs/images/tutorials/deploying-web-applications-with-kubernetes-on-08.png) We are granted a token, in this example: `ghp_vMutK7pgmY1d6hOpF9vGeVpcUB34fd0i7O0j` We need a base64 encoded string which contains the username and the token: ``` ac-demo % echo -n "github-username:ghp_vMutK7pgmY1d6hOpF9vGeVpcUB34fd0i7O0j" | base64< Z2l0aHViLXVzZXJuYW1lOmdocF92TXV0SzdwZ21ZMWQ2aE9wRjl2R2VWcGNVQjM0ZmQwaTdPMGo= ``` Create a new file, `.dockerconfigjson`, with the following content: ``` { "auths": { "https://ghcr.io/ORGANIZATION_NAME/IMAGE_REPOSITORY_NAME":{ "username":"github-username", "password":"ghp_vMutK7pgmY1d6hOpF9vGeVpcUB34fd0i7O0j", "email":"YOUR_EMAIL", "auth":"Z2l0aHViLXVzZXJuYW1lOmdocF92TXV0SzdwZ21ZMWQ2aE9wRjl2R2VWcGNVQjM0ZmQwaTdPMGo=" } } } ``` *Note: This docker config format can be used to authenticate any Docker image repository, not just GHCR* Now encode this entire file, which we will save as the secret. ``` ac-demo % cat .dockerconfigjson | base64 ewogICAgImF1dGhzIjogewogICAgICAgICJodHRwczovL2doY3IuaW8vT1JHQU5JWkFUSU9OX05BTUUvSU1BR0VfUkVQT1NJVE9SWV9OQU1FIjp7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ImdpdGh1Yi11c2VybmFtZSIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ImdocF92TXV0SzdwZ21ZMWQ2aE9wRjl2R2VWcGNVQjM0ZmQwaTdPMGoiLAogICAgICAgICAgICAiZW1haWwiOiJZT1VSX0VNQUlMIiwKICAgICAgICAgICAgImF1dGgiOiJaMmwwYUhWaUxYVnpaWEp1WVcxbE9tZG9jRjkyVFhWMFN6ZHdaMjFaTVdRMmFFOXdSamwyUjJWV2NHTlZRak0wWm1Rd2FUZFBNR289IgogICAgCX0KICAgIH0KfQ== ``` This is the configuration file which will be used to create the Secret, along with a Deployment which uses it to connect to the image repository. ``` apiVersion: v1 kind: Secret metadata: name: registry-credentials namespace: default type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: ewogICAgImF1dGhzIjogewogICAgICAgICJodHRwczovL2doY3IuaW8vT1JHQU5JWkFUSU9OX05BTUUvSU1BR0VfUkVQT1NJVE9SWV9OQU1FIjp7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ImdpdGh1Yi11c2VybmFtZSIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ImdocF92TXV0SzdwZ21ZMWQ2aE9wRjl2R2VWcGNVQjM0ZmQwaTdPMGoiLAogICAgICAgICAgICAiZW1haWwiOiJZT1VSX0VNQUlMIiwKICAgICAgICAgICAgImF1dGgiOiJaMmwwYUhWaUxYVnpaWEp1WVcxbE9tZG9jRjkyVFhWMFN6ZHdaMjFaTVdRMmFFOXdSamwyUjJWV2NHTlZRak0wWm1Rd2FUZFBNR289IgogICAgCX0KICAgIH0KfQ== --- apiVersion: apps/v1 kind: Deployment metadata: name: demo-app namespace: default spec: replicas: 2 selector: matchLabels: app: demo-app strategy: type: RollingUpdate template: metadata: labels: app: demo-app spec: containers: - image: ghcr.io/ORGANIZATION_NAME/IMAGE_REPOSITORY_NAME imagePullPolicy: IfNotPresent name: demo-app env: - name: REACT_APP_ENVIRONMENT value: PROD ports: - containerPort: 8080 imagePullSecrets: - name: registry-credentials ``` ## Use Traefik Ingress (Instead of NGINX) In order to use traefik as an ingress controller, simply run these commands and apply this traefik ingress file instead of using nginx. *Note: You still need to configure an A record to point to your domain.* `helm repo add traefik https://helm.traefik.io/traefik` `helm repo update` `helm install traefik traefik/traefik` traefik-ingress.yaml ``` apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: kubernetes.io/ingress.class: traefik spec: rules: - host: "demo.your_domain" http: paths: - pathType: Prefix path: "/" backend: service: name: demo-svc port: number: 80 ``` ``` ac-demo % kubectl apply -f traefik-ingress.yaml ingress.networking.k8s.io/demo-ingress created ``` ## Enable Autoscaling for your App In order to enable Kubernetes autoscaling follow our [Kubernetes Autoscaling Guide](https://docs.americancloud.com/hc/docs/articles/1722538105-kubernetes-_-autoscaling). ## How to configure CloudPanel backups for A2 storage Rclone is a command-line program used to manage and synchronize files with various cloud storage services and other locations. In this scenario, Rclone is used only for the initial configuration of the A2 object storage, and backups will be performed through the CloudPanel Interface. ## Rclone configuration To configure Rclone you first log in to the server via [SSH](https://docs.americancloud.com/hc/docs/articles/1722537850-managing-ssh-keys). Once you have logged in, please run the following command: `rclone config` The command will open a prompt that looks like the following: To configure Rclone to use A2 storage, the following information is required: - Bucket name - Storage directory - Bucket URL - Secret key - Access key This information can be found in your account under "Object Storage". For more information, please review: [A2 Object Storage](https://docs.americancloud.com/hc/docs/articles/1722538984-a2-object-storage) The easiest way to configure the destination will be to copy the below configuration into the following file: ``` /root/.config/rclone/rclone.conf ``` > **Note:** The name must be [remote] for CloudPanel to detect the configuration: ``` cat /root/.config/rclone/rclone.conf [remote] type = s3 provider = ceph access_key_id = $key_id secret_access_key = $access_key endpoint = a2-west.americancloud.com ``` Make sure to replace $key_id and $access_key with the ones provided under "Object Storage > Bucket > Settings", as shown in the screenshot: ![](/docs/images/tutorials/how-to-configure-cloudpanel-backups-for-a2-storage-01.png) Go back to CloudPanel and configure the bucket name and remote directory: ![](/docs/images/tutorials/how-to-configure-cloudpanel-backups-for-a2-storage-02.png) ## A2 storage If you do not have A2 storage, please review the following article: [A2 storage creation](https://docs.americancloud.com/hc/docs/articles/1722538984-a2-object-storage) ## Testing Backups Once the configuration has been completed, you can test with the following command, which shows remote directories in the bucket and confirms the connection is valid: ``` rclone lsf $remote_bucket_name: -R WordPressBackup/ FullBackup/ ``` ## Creating your first backup To create a manual backup, simply click on "Create Backup" as shown in the screenshot. The backup will be started in the background. ![](/docs/images/tutorials/how-to-configure-cloudpanel-backups-for-a2-storage-03.png) ## How to use MySQL Workbench with Coolify **The below documentation outlines neccessary steps to create a SSH connection between a Coolify MySQL and MySQL Workbench.** ## Set up Instance 1. Create the MySQL resource within Coolify by selecting the project for the resource. The default 'My first project' is utilized for the document. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-01.png) 2. Select the '+Add New Resource'. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-02.png) 3. Select the desired server for the resource. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-03.png) 4. Once the resource list is presented navigate down the page to the databases section. Select 'New MySQL'. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-04.png) 5. Identify the destination for the resource. Either by selecting a previously built or adding a new destination. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-05.png) 6. SSH into the coolify machine. Run the command `sudo docker run --rm -ti --name=ctop -v /var/run/docker.sock:/var/run/docker.sock quay.io/vektorlab/ctop:latest`. This will list containers running on the machine. Using the arrow keys scroll to the MySQL resource and press enter. The container needs to be in a running state to be accessed ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-06.png) 7. The containers listening ports will be listed. This port will be used in the next step. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-07.png) 8. Once the resource is complete, 1) add the desired port to communicate on. In the example port 3000 for the local machine and 3306 for the container. 2) Restart the machine to put the new configs in place. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-08.png) 9. Once restared, check the container to ensure ports are configured appropriately by repeating steps 6&7 above. As an example (below), port 3000 is mapped from the local coolify instance to port 3306 if the mysql container. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-09.png) ## Set up Local Host 1. Set up SSH tunnel on your local machine that is running the MySQL client (ie. mysql or MySQL Workbench) by running the below command. ``` ssh -4 -f -N -T -L 3131:127.0.0.1:3000 cloud@coolify_public_ip_here ``` 2. Open MySQL Workbench and select '+' toggle to add a new connection. ![]() ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-10.png) 3. In the pop up add a name for the connection. Make hostname localhost 127.0.0.1 and port 3131 as set previously. Select test connection. ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-11.png) 4. Provide the MySQL root password from coolify in the MySQL Workbench pop up. Optionally, save the password to keychain for quick launch. ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-12.png) 5. Select the newly built connection. If prompted provide root password. ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-13.png) 6. Select 'Server Status' from the left navigation menu. ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-14.png) 7. Ensure connection and server is running. ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-15.png) ![](/docs/images/tutorials/how-to-use-mysql-workbench-with-coolify-16.png) MySQL Workbench is now connected to the Coolify MySQL resource and editable. ## Installing Ubuntu GUI American Cloud VMs are virtualized computing resources, allowing users to run virtual instances of operating systems and applications in the cloud. GUI integration can make it easier for users to interact with these VMs, especially for tasks that require visual feedback or interactions, such as managing the VM's configurations, accessing file systems, or installing software with graphical installers. ## Update & upgrade system ``` sudo apt update && sudo apt upgrade ``` American Cloud utilize a specific cloud.cfg file so customers can manage their VM's via their CMP dashboard. While running the update && upgrade, the system will ask to use the current configured cloud.cfg or the standard Ubuntu. Choose 'N' so management through the CMP is still possible. ![](/docs/images/tutorials/installing-ubuntu-gui-01.png) ## Install xrdp xrdp is a software tool that allows for remote desktop protocol (RDP) connections to Linux-based operating systems such as Ubuntu. It enables remote access to Ubuntu through a graphical user interface (GUI) from another device over a network connection. - To establish a remote connection to the Ubuntu OS, xrdp will be utilized. Install xrdp on the Virtual Machine to facilitate this connection using the below commands. ``` sudo apt-get install xrdp ``` Newly installed packages and space will be identified by the system. Select 'y' and press enter when promted to continue. ``` 0 upgraded, 266 newly installed, 0 to remove and 0 not upgraded. Need to get 130 MB of archives. After this operation, 489 MB of additional disk space will be used. Do you want to continue? [Y/n] y ``` - enable systemctl to start the process ``` sudo systemctl enable xrdp ``` ## Firewall settings - In the American cloud CMP create a new firewall rule allowing port 3389. ![](/docs/images/tutorials/installing-ubuntu-gui-02.png) > For details on firewall rules, see [Public IPs](/docs/networking/public-ips). - If utilizing UFW on linux ensure port 3389 is open for communication with the following command: ``` sudo ufw allow 3389/tcp ``` ## Create port forwarding rule - In the American cloud CMP create a new port forwarding rule for port 3389. ![](/docs/images/tutorials/installing-ubuntu-gui-03.jpg) > For details on port forwarding, see [Public IPs](/docs/networking/public-ips). ## Install Ubuntu Desktop Ubuntu Desktop is a popular Linux-based operating system designed for desktop and laptop computers. It provides a user-friendly interface with a graphical desktop environment, offering a wide range of pre-installed applications for productivity, web browsing, multimedia, and more. Ubuntu Desktop is known for its stability, security, and open-source nature, making it a popular choice for individuals, businesses, and educational institutions seeking a free and powerful operating system. - The below command will install Ubuntu Desktop. This will take several minutes to finish. ``` sudo apt-get install ubuntu-desktop ``` - Reboot the Virtual Machine to ensure everything gets saved properly. ``` sudo reboot ``` ## Mac: Connect to GUI on Mac > **Note:** For this tutorial Microsoft Remote Desktop will be used. In the app store search and install the Microsoft Remote Desktop. There are several remote desktop applications that may work as well. ### Download Microsoft Remote Desktop In the app serch field type 'Microsoft Remote Desktop' press enter. The first application will be Microsoft Remote Desktop, select 'GET'. After a few seconds the application will be downloaded and installed on the system. ![](/docs/images/tutorials/installing-ubuntu-gui-04.png) > **Note:** The picture shows open b/c the application has already been installed on this machine. ### Using Microsoft Remote Desktop Microsoft Remote Desktop is a software application that allows users to remotely access and control Windows-based computers or servers from another device, such as a computer, tablet, or mobile device. It uses the Remote Desktop Protocol (RDP) to establish a secure connection between the local device and the remote Windows-based computer, enabling users to interact with the remote desktop as if they were physically present at that computer. Microsoft Remote Desktop is widely used for remote work, technical support, and server administration, among other purposes. - Follow the steps below to connect to Ubuntu Desktop previously installed 1. Select 'Launchpad' from the tool bar. 2. Select 'Microsoft Remote Desktop' **Input connection information** - The application will launch with a single 'Add PC' switch. Select 'Add PC' or if desired the toolbar to the top select '+' icon. ![](/docs/images/tutorials/installing-ubuntu-gui-05.png) - A new window will appear requesting PC information. In the PC name field input the Public IP of the virtual machine Ubuntu Desktop is running. Additionally, if desired add and save the user account information. Once complete select add. ![](/docs/images/tutorials/installing-ubuntu-gui-06.png) > For help finding the Public IP within the AC CMP, [Click Here](/docs/networking/createmanage-a-virtual-private-cloud-network). ### Connect to the desktop - In the main application window the the new machine will be added. ![](/docs/images/tutorials/installing-ubuntu-gui-07.png) - Now select the three dot toggle on the lower right of the machine and select 'Connect'. ![](/docs/images/tutorials/installing-ubuntu-gui-08.png) - A warning window will populate. Select 'Connect' ![](/docs/images/tutorials/installing-ubuntu-gui-09.png) - In the popup provide the account credentials. ![](/docs/images/tutorials/installing-ubuntu-gui-10.png) - **The new connection has been made.** ![](/docs/images/tutorials/installing-ubuntu-gui-11.png) ## Windows: Connect to GUI on Windows - In windows this tutorial will utilize the built-in 'Remote Desktop Connection' software. ### Open Remote Desktop Connection - In the windows tool bar search field type 'Remote desktop connection' ![](/docs/images/tutorials/installing-ubuntu-gui-12.png) - In the windows popup window select 'Windows Remote Desktop' ![](/docs/images/tutorials/installing-ubuntu-gui-13.png) ### Connect to Ubuntu Desktop 1. Once the software starts, place the public IP in the computer name text box. ![](/docs/images/tutorials/installing-ubuntu-gui-14.png) > For help identifying the public IP, [Click Here](/docs/networking/createmanage-a-virtual-private-cloud-network). - If desired select the grey arrow in the lower left for more options and add user information. ![](/docs/images/tutorials/installing-ubuntu-gui-15.png) - Select 'Connect'. A warning window will populate select 'Yes' in order to continue. ![](/docs/images/tutorials/installing-ubuntu-gui-16.png) - Next sign into the account to continue to the Ubuntu Desktop. ![](/docs/images/tutorials/installing-ubuntu-gui-17.png) - Now the Ubuntu Desktop sign-in will appear. Sign in using the appropriate credintials. ![](/docs/images/tutorials/installing-ubuntu-gui-18.png) - That's it. It's connected. ## Mount or Unmount Drives ## List All Partitions Running the lsblk the available drives will be provided ``` lsblk ``` Once command is ran a read-out will be provided showing available drives similar to below. In this example the volume vdb size 50G is block-storage_1 inside the American Cloud CMP. Additionally, below we can see vdb is not mounted. ``` cloud@Compute-1:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 63.3M 1 loop /snap/core20/1822 loop1 7:1 0 91.9M 1 loop /snap/lxd/24061 loop2 7:2 0 49.9M 1 loop /snap/snapd/18357 loop3 7:3 0 63.3M 1 loop /snap/core20/1852 sr0 11:0 1 1024M 0 rom vda 252:0 0 25G 0 disk ├─vda1 252:1 0 24.9G 0 part / ├─vda14 252:14 0 4M 0 part └─vda15 252:15 0 106M 0 part /boot/efi vdb 252:16 0 50G 0 disk ``` ## Partition Drive - Partitioning a drive involves dividing it into one or more logical sections, each of which acts as a separate drive with its own file system. This can be useful for various reasons, such as isolating data for backup or security purposes, installing multiple operating systems on a single drive, or organizing files and folders more efficiently. Partitioning can be done using various tools, such as Disk Management in Windows, Disk Utility in macOS, or fdisk in Linux. - In this example fdisk command will be utilized 1. Identify the drive to partition using `fdisk -l` ``` sudo fdisk -l Disk /dev/loop0: 49.84 MiB, 52260864 bytes, 102072 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/loop1: 111.95 MiB, 117387264 bytes, 229272 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes ``` 2. Use fdisk command to partition the drive. - Identify the drives path. For this example /dev/vdb1 will be placed in fdisk command. This information was retrieved running fdisk -l above ``` sudo fdisk /dev/vdb1 ``` - A readout similar to the below will be displayed confirming drive is open using fdisk command ``` Welcome to fdisk (util-linux 2.37.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. The device contains 'ext4' signature and it will be removed by a write command. See fdisk(8) man page and --wipe option for more details. Device does not contain a recognized partition table. Created a new DOS disklabel with disk identifier 0x11b600de. Command (m for help): ``` - fdisk command is a letter based operation where a letter is assigned to a command. Notice (m for help). Press 'm' and enter to enter help mode and print command layout. The first couple of columns are printed below ``` Command (m for help): m Help: DOS (MBR) a toggle a bootable flag b edit nested BSD disklabel c toggle the dos compatibility flag Generic d delete a partition F list free unpartitioned space l list known partition types n add a new partition p print the partition table t change a partition type v verify the partition table i print information about a partition ``` - Create new partition using 'n' command ``` Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p ``` - In the about command once the 'n' command has been given fdisk command request information on the partition type. Here a primary partition will be built identified by the 'p' command. Next we'll be asked the sector in which to build the new partition. The first (1) sector will be selected ``` Partition number (1-4, default 1): 1 ``` - Following the above we'll determine the size of the sector/partition. ``` Last sector, +/-sectors or +/-size{K,M,G,T,P} (10000-97654783, default 97654783): +10G ``` - The new partition of 10G has been built by fdisk command ``` Created a new partition 1 of type 'Linux' and of size 10 GiB. ``` - Notice partition type defaulted to 'Linux in the above read out. fdisk will automatically defualt to 'Linux' In order to change this use the 't' command. Following the 't' command a 'L' command can be given to list all available types ``` 1 EFI System C12A7328-F81F-11D2-BA4B-00A0C93EC93B 2 MBR partition scheme 024DEE41-33E7-11D3-9D69-0008C781F39F 3 Intel Fast Flash D3BFE2DE-3DAF-11DF-BA40-E3A556D89593 4 BIOS boot 21686148-6449-6E6F-744E-656564454649 5 Sony boot partition F4019732-066E-4E12-8273-346C5641494F 6 Lenovo boot partition BFBFAFE7-A34F-448A-9A5B-6213EB736C22 7 PowerPC PReP boot 9E1A2D38-C612-4316-AA26-8B49521E5A8B 8 ONIE boot 7412F7D5-A156-4B13-81DC-867174929325 9 ONIE config D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149 10 Microsoft reserved E3C9E316-0B5C-4DB8-817D-F92DF00215AE 11 Microsoft basic data EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 12 Microsoft LDM metadata 5808C8AA-7E8F-42E0-85D2-E1E90434CFB3 13 Microsoft LDM data AF9B60A0-1431-4F62-BC68-3311714A69AD 14 Windows recovery environment DE94BBA4-06D1-4D40-A16A-BFD50179D6AC 15 IBM General Parallel Fs 37AFFC90-EF7D-4E96-91C3-2D7AE055B174 16 Microsoft Storage Spaces E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D 17 HP-UX data 75894C1E-3AEB-11D3-B7C1-7B03A0000000 18 HP-UX service E2A1E728-32E3-11D6-A682-7B03A0000000 19 Linux swap 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F 20 Linux filesystem 0FC63DAF-8483-4772-8E79-3D69D8477DE4 21 Linux server data 3B8F8425-20E0-4F3B-907F-1A25A76F98E8 22 Linux root (x86) 44479540-F297-41B2-9AF7-D131D5F0458A 23 Linux root (x86-64) 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 24 Linux root (ARM) 69DAD710-2CE4-4E3C-B16C-21A1D49ABED3 : ``` - Now the new partition is saved in memory and waiting to be written to disk. To review the newly built partition use the 'p' command ``` Command (m for help): p Disk /dev/vdb: 50 GiB, 53687091200 bytes, 104857600 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 0831ABEB-082B-4EF1-AA79-E22EE04FFF74 Device Start End Sectors Size Type /dev/vdb1 2048 20973567 20971520 10G Linux filesystem ``` - To write the changes use the 'w' command. This will write the newly developed partition to the disk ``` Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. ``` - Using `sudo fdisk -l` double check the build of the new partition ## Format Drive There are different types of Linux format like btrfs, ext2, ext4, xfs, cramfs, ext3 and minix that are compatible with the Linux operating system ### BTRFS - Btrfs: A modern file system for Linux operating systems that provides features such as snapshots, compression, and checksums for data integrity. It is designed to improve performance, scalability, and manageability of file storage on modern systems. ### EXT2 - Ext2: A traditional file system for Linux operating systems that was introduced in the early 1990s. It provides support for basic file and directory operations and has been widely used in Linux distributions. However, it lacks some modern features such as journaling and dynamic resizing. ### EXT4 - Ext4: A modern file system for Linux operating systems that provides features such as journaling, support for large files and directories, and improved performance and scalability. It is the default file system in many Linux distributions and is widely used in production environments. ### XFS - XFS: A high-performance file system for Linux and other Unix-like operating systems. It was designed for scalability, supporting file systems up to 16 exabytes in size, and is optimized for handling large files and high-volume data throughput. XFS is widely used in enterprise and cloud environments. ### CRAMFS - Cramfs (Compressed ROM File System): A read-only file system commonly used in embedded systems such as routers, set-top boxes, and smartphones. It is designed to save storage space by compressing the file system and is loaded into memory at boot time for fast access. ### EXT3 - Ext3: A journaled file system for Linux operating systems that was introduced in 2001. It provides support for basic file and directory operations and also includes a journaling system for improved reliability and faster recovery from crashes. Ext3 is widely used in Linux distributions but has been largely replaced by Ext4. ### MINIX - MINIX: A file systems using a simple structure consisting of a boot block, superblock, and inode block. To format the drive follow the following steps: 1. Identify drive to format. If partitioning occured in the above step select the partition. 2. Run the below command to format drive. If desired change `ext4` to different format. ``` sudo mkfs.ext4 /dev/vdb1 ``` - Readout should look similar to: ``` mke2fs 1.46.5 (30-Dec-2021) Discarding device blocks: done Creating filesystem with 12206848 4k blocks and 3055616 inodes Filesystem UUID: a86a8d51-0ed0-4818-9c81-b7afb8c77309 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424 Allocating group tables: done Writing inode tables: done Creating journal (65536 blocks): done Writing superblocks and filesystem accounting information: done ``` - The drive is now formatted to ext4 ## Create Mount Point A mount point directory is a directory in a file system that serves as a reference point for accessing a storage device or a partition. When a storage device is connected to a computer or server, it must be mounted to be accessed by the system. Create the directory within /mnt by running the following command. ``` sudo mkdir /mnt/vdb1 ``` - To check creation run: ``` ls /mnt ``` ## Mount the Partition - Now that the new partition has been built, formatted, and created a mount point. Mount the partition. The below commands will be ran ``` sudo mount /dev/vdb1 /mnt/vdb1 ``` - There will not be a readout from this command. To check mounting use command `lsblk` as described in previous steps ``` cloud@Compute-AC-9:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 49.8M 1 loop /snap/snapd/18357 loop1 7:1 0 111.9M 1 loop /snap/lxd/24322 loop2 7:2 0 63.3M 1 loop /snap/core20/1828 loop3 7:3 0 63.3M 1 loop /snap/core20/1852 loop4 7:4 0 53.2M 1 loop /snap/snapd/18933 sr0 11:0 1 1024M 0 rom vda 252:0 0 25G 0 disk ├─vda1 252:1 0 24.9G 0 part / ├─vda14 252:14 0 4M 0 part └─vda15 252:15 0 106M 0 part /boot/efi vdb 252:16 0 50G 0 disk └─vdb1 252:17 0 10G 0 part /mnt/vdb1 ``` - In the above, vdb1 has been mounted to /mnt/vdb1 as depicted in the MOUNTPOINTS column > **Note:** The example uses partitions and drives on the local machine. Ensure to use accurate [paths] on your local machine. ## Unmount Partition - A drive can be unmounted using the 'umount' command ``` sudo umount /dev/vdb1 ``` - There will be no readout from this command. To check the success of the operation use the 'lsblk' command ``` lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 49.8M 1 loop /snap/snapd/18357 loop1 7:1 0 111.9M 1 loop /snap/lxd/24322 loop2 7:2 0 63.3M 1 loop /snap/core20/1828 loop3 7:3 0 63.3M 1 loop /snap/core20/1852 loop4 7:4 0 53.2M 1 loop /snap/snapd/18933 sr0 11:0 1 1024M 0 rom vda 252:0 0 25G 0 disk ├─vda1 252:1 0 24.9G 0 part / ├─vda14 252:14 0 4M 0 part └─vda15 252:15 0 106M 0 part /boot/efi vdb 252:16 0 50G 0 disk └─vdb1 252:17 0 10G 0 part ``` - Notice the mountpoint has been removed from vdb1 > **Note:** If desired use fdisk to remove partition from drive. All the examples have been built on an American Cloud CMP Block Storage drive. ## s3cmd (Simple Storage Service Command Line Tool and API) `s3cmd` is a command-line tool for working with S3-compatible object storage. It lets you create buckets, upload and download files, and manage objects using standard S3 operations — all from your terminal or scripts. American Cloud A2 Object Storage is S3-compatible, so `s3cmd` works against it once you point it at the correct endpoint and enter your keys. Follow the steps below to install and configure it. ## Install On Debian/Ubuntu: ``` sudo apt install s3cmd ``` On macOS (Homebrew): ``` brew install s3cmd ``` ## Configure s3cmd `s3cmd` needs three things: your Object Storage **access key**, your **secret key**, and the **endpoint** for your region. ### Get your keys and endpoint 1. Sign in to the American Cloud CMP. 2. In the left navigation, choose **Storage**. 3. On the **A2 Object Storage** tab, select **Manage**. 4. Open Object Storage **Settings**, then select **Keys** to view your access key and secret key. Your **endpoint** is the regional host shown in the CMP. For the West region it is `a2-west.americancloud.com`. Use the endpoint for the region your bucket lives in. ### Recommended: create the config file directly The quickest and most reliable way to set up `s3cmd` for American Cloud is to write the config file yourself — it avoids a wizard prompt that's easy to get wrong (see the note below). Create `~/.s3cfg` with the following contents, replacing the two key values with your own: ``` [default] access_key = YOUR_ACCESS_KEY secret_key = YOUR_SECRET_KEY host_base = a2-west.americancloud.com host_bucket = a2-west.americancloud.com use_https = True ``` That's everything `s3cmd` needs. Note that `host_base` and `host_bucket` are set to the **same value** — this tells `s3cmd` to use path-style addressing (`https://a2-west.americancloud.com/your-bucket`), which is what A2 Object Storage expects. Verify it works by listing your buckets: ``` s3cmd ls ``` If your keys and endpoint are correct, this returns your buckets (or nothing at all, if you haven't created any yet) with no error. ### Alternative: the `s3cmd --configure` wizard You can also configure interactively, but **one prompt is easy to get wrong** — read the note before running it. Start the wizard with: ``` s3cmd --configure ``` Enter the following values, pressing **Enter** to accept the default for anything not listed: | Prompt | Enter | | --- | --- | | Access Key | your access key | | Secret Key | your secret key | | Default Region [US] | leave default (press Enter) | | S3 Endpoint | `a2-west.americancloud.com` | | DNS-style bucket+hostname:port template | `a2-west.americancloud.com` | | Encryption password | leave blank | | Path to GPG program | leave default | | Use HTTPS protocol [Yes] | leave default | | HTTP Proxy server name | leave blank | When prompted, choose **Y** to run the connection test, then **Y** to save. The wizard writes your settings to `~/.s3cfg`. ### Editing the config later To rotate keys or change your endpoint at any time, edit `~/.s3cfg` directly: ``` nano ~/.s3cfg ``` Make sure both `host_base` and `host_bucket` point at your regional endpoint (e.g. `a2-west.americancloud.com`) and that your `access_key` and `secret_key` are current. A correct file looks like this: ``` [default] access_key = YOUR_ACCESS_KEY secret_key = YOUR_SECRET_KEY host_base = a2-west.americancloud.com host_bucket = a2-west.americancloud.com use_https = True ``` ## Add Buckets Object storage buckets are containers for storing and organizing large volumes of unstructured data, such as files, images, and videos, in the cloud. They provide scalable, durable, and cost-effective storage solutions, allowing users to upload, retrieve, and manage data using APIs or web interfaces. Below are list of commands for adding buckets. ### Make Bucket Command ``` # Use mb (make bucket) command s3cmd mb s3://americancloud-1 ``` ``` cloud@Compute-1:~$ s3cmd mb s3://americancloud-1 Bucket 's3://americancloud-1/' created ``` - Using the ls command list buckets. ``` s3cmd ls ``` - The new bucket is listed. ``` cloud@Compute-1:~$ s3cmd ls 2023-04-19 23:46 s3://americancloud-1 2023-04-19 21:02 s3://bucketac2 ``` - As expected the bucket has been placed inside AC CMP. ## Removing a Bucket Removing buckets is a process that permanently deletes a bucket and all its objects. To remove a bucket, the user must have appropriate permissions, and all objects within the bucket must be deleted first. Once a bucket is removed, its data cannot be recovered. It is important to exercise caution and ensure backups are in place before deleting any buckets in S3. ### Remove Bucket Command ``` s3cmd rb ``` ``` cloud@Compute-1:~$ s3cmd rb s3://ac-123 Bucket 's3://ac-123/' removed ``` - CMP side the bucket has been removed as well. ## List Buckets and Files Listing files in S3 involves retrieving a list of objects (files) stored within a specific bucket. The list typically includes information such as object names, sizes, and metadata. It can be useful for navigating and managing objects in S3, including copying, deleting, or downloading files. Proper access permissions and authentication are required to list files in S3, ensuring data security and privacy. ### List command - The ls command will list the buckets within Object Storage. ``` s3cmd ls ``` ``` cloud@Compute-1:~$ s3cmd ls 2023-04-19 23:46 s3://americancloud-1 2023-04-20 17:51 s3://americancloud-2 ``` - List files within a bucket by running the ls s3://*bucketname. ``` s3cmd ls s3://americancloud-1 ``` ``` cloud@Compute-1:~$ s3cmd ls s3://americancloud-1 2023-04-20 03:16 89.6904296875k s3://americancloud-1/AC is Awesome.pages 2023-04-20 00:39 148.197265625k s3://americancloud-1/Screenshot 2023-04-19 at 6.52.20 PM-20230420123958.png 2023-04-20 00:20 148.90234375k s3://americancloud-1/Screenshot 2023-04-19 at 7.19.54 PM-20230420122021.png 2023-04-20 17:15 0 s3://americancloud-1/americancloudisawesome.txt 2023-04-20 17:14 0 s3://americancloud-1/sample.txt ``` - Additionally, list all files within all buckets by executing s3cmd la. ``` s3cmd la ``` ``` cloud@Compute-1:~$ s3cmd la 2023-04-20 03:16 89.6904296875k s3://americancloud-1/AC is Awesome.pages 2023-04-20 00:39 148.197265625k s3://americancloud-1/Screenshot 2023-04-19 at 6.52.20 PM-20230420123958.png 2023-04-20 00:20 148.90234375k s3://americancloud-1/Screenshot 2023-04-19 at 7.19.54 PM-20230420122021.png 2023-04-20 17:15 0 s3://americancloud-1/americancloudisawesome.txt 2023-04-20 17:14 0 s3://americancloud-1/sample.txt 2023-04-20 17:52 0 s3://americancloud-2/americancloudisawesome.txt ``` ## Add Files The "put" command in S3 is a command-line operation that allows users to upload (put) objects (files) from their local system to an S3 bucket. The "put" command requires specifying the source file path, destination S3 bucket name, and object key (file name) to store the object in S3. Proper permissions and authentication are necessary for successful object uploads. ### PUT Command - Single file upload ``` s3cmd put /file s3://americancloud-1 ``` ``` s3cmd put americancloudisawesome.txt s3://americancloud-1 upload: 'americancloudisawesome.txt' -> 's3://americancloud-1/americancloudisawesome.txt' [1 of 1] 0 of 0 0% in 0s 0.00 B/s done ``` - Multiple file upload ``` s3cmd put ac1.txt ac2.txt path/to/ac3.txt s3://americancloud-1 ``` ``` s3cmd put acisawesome.txt americancloudisawesome.txt s3://bucketac4 upload: 'acisawesome.txt' -> 's3://bucketac4/acisawesome.txt' [1 of 2] 0 of 0 0% in 0s 0.00 B/s done upload: 'americancloudisawesome.txt' -> 's3://bucketac4/americancloudisawesome.txt' [2 of 2] 0 of 0 0% in 0s 0.00 B/s done ``` - Change name during upload ``` s3cmd put ac1.txt s3://americancloud-1/newname.txt ``` ``` s3cmd put test.txt s3://bucketac4/ac-2.txt upload: 'test.txt' -> 's3://bucketac4/ac-2.txt' [1 of 1] 0 of 0 0% in 0s 0.00 B/s done ``` - If desired an entire director can be moved using 'sync' command. Idea for backup scenarios ``` cloud@Compute-AC-9:~$ s3cmd sync /home/cloud s3://bucketac4 upload: '/home/cloud/.bash_history' -> 's3://bucketac4/cloud/.bash_history' [1 of 12] 0 of 0 0% in 0s 0.00 B/s done upload: '/home/cloud/.bash_logout' -> 's3://bucketac4/cloud/.bash_logout' [2 of 12] 220 of 220 100% in 0s 7.99 KB/s done upload: '/home/cloud/.bashrc' -> 's3://bucketac4/cloud/.bashrc' [3 of 12] ``` ## Retrieving Files To retrieve files in S3, a cloud-based object storage service, you can use the S3 API or S3 console. First, authenticate and authorize access, then specify the S3 bucket and object key to identify the file. Use the appropriate method, such as GET, to retrieve the file from S3. Optionally, you can configure access control and encryption settings for added security. ### GET Command #### Single file download ``` s3cmd get s3://[bucketname]/filename ``` ``` s3cmd get s3://bucketac4/ac-2.txt download: 's3://bucketac4/ac-2.txt' -> './ac-2.txt' [1 of 1] 0 of 0 0% in 0s 0.00 B/s done ``` #### Multiple file download ``` s3cmd get s3://bucketac4/test1.txt s3://bucketac4/test2.txt download: 's3://bucketac4/test1.txt' -> './test1.txt' [1 of 2] 0 of 0 0% in 0s 0.00 B/s done download: 's3://bucketac4/test2.txt' -> './test2.txt' [2 of 2] 0 of 0 0% in 0s 0.00 B/s done ``` #### Change file name ``` s3cmd get s3://[bucketname]/filename newfilename ``` ``` s3cmd get s3://bucketac4/ac-4.txt ac-5.txt --recursive download: 's3://bucketac4/ac-4.txt' -> 'ac-5.txt' [1 of 1] 0 of 0 0% in 0s 0.00 B/s done ``` #### Use of --recursive. To pull all files from a bucket use the recursive flag. ``` s3cmd get s3://[bucketname]/ --recursive ``` ``` s3cmd get s3://bucketac4/ --recursive download: 's3://bucketac4/Screenshot 2023-04-18 at 11.03.46 PM-20230423120714.png' -> './Screenshot 2023-04-18 at 11.03.46 PM-20230423120714.png' [1 of 10] 512226 of 512226 100% in 0s 1229.82 KB/s done download: 's3://bucketac4/Screenshot 2023-04-21 at 5.20.19 PM-20230423120721.png' -> './Screenshot 2023-04-21 at 5.20.19 PM-20230423120721.png' [2 of 10] 42789 of 42789 100% in 0s 432.86 KB/s done ``` ## Removing Files Deleting a file in S3 is a straightforward process. Deleted files cannot be retrieved. ### Remove Command #### Remove files ``` s3cmd rm s3://[bucketname]/filename ``` ``` s3cmd rm s3://bucketac4/ac-5.txt delete: 's3://bucketac4/ac-5.txt' ``` #### Remove multiple files ``` s3cmd rm s3://bucketac4/ac-2.txt s3://bucketac4/ac-4.txt delete: 's3://bucketac4/ac-2.txt' delete: 's3://bucketac4/ac-4.txt' ``` #### Remove all files from a bucket use the recursive and force flag. ``` s3cmd rm s3://[bucketname]/ --recursive --force ``` ``` cloud@Compute-1:~$ s3cmd rm s3://bucketac4/ --recursive --force delete: 's3://bucketac4/Screenshot 2023-04-18 at 11.03.46 PM-20230423120714.png' delete: 's3://bucketac4/Screenshot 2023-04-21 at 5.20.19 PM-20230423120721.png' ``` ## Setting Domain Registrar's Nameservers to American Cloud Nameservers Although American Cloud is not a domain registrar our free DNS Manager will work with any domain registrar. Using American Cloud DNS Manager you will need to set your domain registrar to use American Cloud's nameservers. Below are step-by-step guides on how to find your domain registrar and how to change nameservers for popular domain registrars. American Cloud Nameservers can be located in the American Cloud App in your DNS Management portal ## Looking up your Domain Registrar To lookup your domain's registrar you can use [https://www.whois.com/whois/](https://www.whois.com/whois/) to enter your domain and click search. ![](/docs/images/tutorials/setting-domain-registrars-nameservers-to-american-01.png) The results will provide you with your domain registrar information. ![](/docs/images/tutorials/setting-domain-registrars-nameservers-to-american-02.png) ## Changing your Nameservers Now that you know your domain registrar, you will need to login to your registrar account. Once you are logged into please use the below guides for your domain registrar to change the naeservers. ### easyDNS 1. Log into your easyDNS account. 2. Click on WHOIS. 3. Under NAME SERVERS click on EDIT. 4. Enter your name servers in the spaces provided. You can also click on the link to use the default easyDNS name servers for your domain. 5. Click NEXT. 6. Confirm your changes. ### NameCheap 1. Sign in to your Namecheap account. 2. Select Domain List from the left sidebar and click the Manage button next to your domain: 3. Find the Nameservers section and select your preferred option from the drop-down menu. Click on the green checkmark to save the changes: ### GoDaddy 1. Sign in to your GoDaddy Domain Portfolio. 2. Select the checkbox for domain being changed 3. Select Nameservers from the action menu. 4. Choose the nameserver setting, I'll use my own nameservers 5. Enter your custom nameservers. 6. Select Save, then Continue to complete your updates. ### HostGator 1. Sign in to your HostGator Customr Portal. 2. Click on Domains on the left menu. 3. Click on the More button for the domain to be updated. 4. Click on the Change link under the Name Servers 5. Enter American Cloud's nameservers. WARNING: When changing nameservers at the registrar, it can take up to 24-48 hours for DNS propagation time, where your website and email may not be available. ## Using Node.js to upload files to A2 Storage 1. Login to the Web Portal with a valid American Cloud account 2. Go to Cloud Compute and select the VM to install Node.js on. If no VM is created yet [Click Here](https://docs.americancloud.com/hc/docs/articles/1722537204-cloud-compute). 3. Get the password and public IP for the cloud user of the VM to SSH into the VM 4. SSH into the VM `ssh cloud@"PublicIP"` ## Install and configure Node.js 1. Run `sudo apt-get update` to ensure repositories are up to date 2. Install Node.js onto the VM using `sudo apt install nodejs` 3. Verify Node.js installed using `node -v` 4. Run `sudo apt install npm` to be able to install dependecies 5. Once Node.js is installed a dependency will need to be install `npm install aws-sdk` 6. Create a Node.js script to upload a file `sudo nano upload-to-a2.js` ``` const AWS = require('aws-sdk'); const fs = require('fs'); // Configure AWS SDK with your A2 endpoint and credentials const s3 = new AWS.S3({ endpoint: 'YOUR_A2_ENDPOINT', // Replace with your A2 endpoint. Don't include https:// accessKeyId: 'YOUR_ACCESS_KEY', secretAccessKey: 'YOUR_SECRET_KEY', s3ForcePathStyle: true, region: 'a2-west', // This doesn't need to be specific it can be anything }); // Define the bucket name and file name const bucketName = 'your-bucket-name'; const fileName = 'file-to-upload.txt'; // Rename or code to automatically generate names for files const tenant = 'YOUR_TENANT_ID' ; // Read the file const fileContent = fs.readFileSync(fileName); // Construct the URL with endpoint preceding the bucket name const fileURL = `https://${s3.config.endpoint}/${tenant}:${bucketName}/${fileName}`; // Create parameters for A2 upload const params = { Bucket: bucketName, Key: fileName, // The name you want to give to the file in A2 Body: fileContent, ACL: 'public-read', // Set to different permissions if needed }; // Upload file to A2 Storage s3.upload(params, (err, data) => { if (err) { console.error('Error uploading file:', err); } else { console.log('File uploaded successfully. File URL:', fileURL); } }); ``` ### "YOUR_A2_ENDPOINT" ![](/docs/images/tutorials/using-nodejs-to-upload-files-to-a2-storage-01.png) Copy the bucket URL the only thing needed will be the "[region.americancloud.com](http://region.americancloud.com/)" for the endpoint ### "your-bucket-name" ![](/docs/images/tutorials/using-nodejs-to-upload-files-to-a2-storage-02.png) ### "YOUR_TENANT_ID" ![](/docs/images/tutorials/using-nodejs-to-upload-files-to-a2-storage-03.png) For testing create a file to test uploading `touch file-to-upload.txt` ## Create Object Storage - To create and get the information needed from the A2 Storage [Click Here](https://docs.americancloud.com/hc/docs/articles/1722538984-a2-object-storage). ## Final Step Once Node.js is installed and configured and the A2 storage is setup. This command can be used to run the script `node upload-to-a2.js` ### Below is the successful output. ![](/docs/images/tutorials/using-nodejs-to-upload-files-to-a2-storage-04.png) ## Using SSH (Secured Shell) SSH stands for Secure Shell, and it is a secure network protocol that allows for remote access and control of a computer or server over an unsecured network. It is commonly used by system administrators and developers to securely manage and transfer data between computers over the internet. When connecting to a remote server using SSH, the connection is encrypted, which means that no one can eavesdrop on the communication or steal the login credentials. The encryption ensures that all data, including passwords and other sensitive information, is transmitted securely over the network. To use SSH, it's neccessary to have an SSH client installed on the computer, and the remote server must have an SSH server installed. Also needed is a username and password or a public/private key pair to authenticate to the remote server. Once authenticated, a command-line interface can be utilized to execute commands on the remote server or transfer files securely between computers and the remote server. SSH also allows for the creatation of encrypted tunnels to forward other network services such as HTTP or FTP, making it an essential tool for secure remote access and administration. ## Basic Usage ### Locate Required Credentials - In order to being the connection an IP address/Hostname, Username,and Password are required. In the American Cloud CMP this information can be found in the compute section. Follow the steps below to acquire the information 1. Login to the Web Portal with a valid American Cloud account 2. On the left navigation column choose 'Cloud Compute' 3. In Manage Instance select the desired instance to SSH into - Inside the 'Server Information' page retreive the public IP address, username (default cloud), and copy the password (default is a randomly selected password) ![](/docs/images/tutorials/using-ssh-secured-shell-01.png) ### SSH The Machine - Open a terminal or cmd prompt and type the following command ``` ssh cloud@[IPAddress] ``` ``` ssh cloud@0.0.0.0 The authenticity of host '0.0.0.0 (0.0.0.0)' can't be established. ED25519 key fingerprint is SHA256:EXAMPLEp01iD6zXvKCF+QdF5VLl3MiFrITEXAMPLE. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? ``` 1. If this is the first login, a message asking to save the fingerprint will appear. Type 'yes' to continue 2. Next enter the password for the User being logged into ``` cloud@0.0.0.0's password: ``` ## SSH with Keys When using SSH keys, authentication to a remote server is possible without having to enter a password while logging in. Instead, a generated pair of cryptographic keys: a public key and a private key. The public key is uploaded to the remote server, while the private key is stored securely on the local computer. When connecting to the remote server using SSH, the server checks the public key against a list of authorized keys. If the public key is on the list, the server uses it to encrypt a message that can only be decrypted with the paired private key. The server sends this encrypted message back to the local computer, and the local SSH client uses the private key to decrypt the message and authenticate to the server. Using SSH keys has several advantages over using a password for authentication. First, it is more secure because it is much harder for an attacker to guess or steal a private key than it is for them to crack your password. Second, it is more convenient because typing a password every time log in isn't neccessary. And third, it is easier to automate scripts or other processes that require remote access, since the private key can be included in the scripts without having to store a password in plain text. To use SSH keys, first generate a key pair using a tool like ssh-keygen. Then copy the public key to the remote server using a command like ssh-copy-id or by manually appending the public key to the authorized_keys file on the remote server. Finally, configure the SSH client to use the private key when connecting to the remote server. - Follow the steps below to SSH a server 1. Generate the SSH key pair For more information on generating key pairs [Click Here](https://docs.americancloud.com/hc/docs/articles/1722537850-managing-ssh-keys). 2. Save the newly generated SSH key pair to the '/.ssh' directory 3. Place the Public Key in the '/.ssh/authorize_keys' directory - There are two primary ways to accomplish step 3 discussed below ### ssh-copy-id - The ssh-copy-id command is an easy way to add the local machines public key to the remote servers /.ssh/authorized_keys directory. To accomplish this follow the below commands ``` ssh-copy-id cloud@[IPAddress] ``` - After pressing enter the remote server will being receiving ssh key pairs from the local machine. As shown the user's password will be required for completion ``` ssh-copy-id cloud@0.0.0.0 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/work/.ssh/id_ed25519.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys cloud@0.0.0.0's password: ``` - Following an accurate password the system will show the number of keys imported and log out ``` Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'cloud@0.0.0.0'" and check to make sure that only the key(s) you wanted were added. ``` Next log back into the remote server using the standard ssh command. If a passphrase was established during generation it will be requested ``` ssh cloud@0.0.0.0 Enter passphrase for key '/Users/joeevans/.ssh/id_ed25519': ``` - A connection not requiring user password will be made ### Placing Public Key in Authorized_keys directory - Another way to accomplish placing a public key into the /.ssh/authorized_keys directory is below. Follow these steps 1. On the local machine naviate to the /.ssh directory. 2. Copy the desired public key. 3. Log into the remote server using the username/password ``` ssh cloud@0.0.0.0 ``` 4. Edit the /.ssh/authorized_keys using the preferred editor. ``` vi /.ssh/authorized_keys ``` 5. Paste the copied public key from the local machine inside the folder ``` ssh-ed25519 Example333lZDI1aaaAAAAIxxxghuGkFSh4256QQoDC+DI5vMwi2EXAMPLE ``` 6. Log out of the remote server using the 'exit' command - It is now possible to log in without needing the user's password. Again if a passphrase was used while generating the key pair input it here. --- # FAQs Frequently asked questions ## Can I change the CIDR of an existing network? CIDR changes are restricted when IP reservations exist or if the new CIDR isn't a valid subset. It is typically more practical to establish a fresh network with the appropriate CIDR parameters from the outset. This approach avoids the limitations and complications associated with modifying existing network configurations that may have dependencies or reservation constraints. ## Can I log in with the root user? Virtual machines are initially created with the "cloud" username, which has sudo privileges. You can modify the VM creation script to enable root. Please review the following article: [Create a VM with the root user](https://docs.americancloud.com/hc/docs/articles/1738366932-instance-creation-with-root-ssh-permitted) ## Can I request specific IP addresses (e.g., within the 25.140.100.x subnet) when purchasing cloud computing resources from your platform? Our system automatically manages and distributes IP addresses from our available pool. When you create a new compute instance, it is automatically assigned one dedicated public IP address. If additional public IPs are required, they can be purchased and managed separately. However, we do not support manual assignment of IPs within a specific subnet. ## Can the global internet infrastructure block American Cloud from operating? American Cloud operates its own network and recursive DNS servers, so from an infrastructure standpoint, we can guarantee uptime and won’t be shut down. However, if major global providers block access to our IP space, it could impact performance due to longer data routing paths. Proper system design can help mitigate these effects. ## Can we move existing VMs to new VPC networks without recreating them? Yes, you can move VMs to new networks by updating their NIC configurations. After completing the network migration, administrators should re-enable static NAT for each VM to restore proper network address translation functionality. This approach offers a more efficient alternative to the traditional method of recreating VMs entirely when network changes are needed. ## How can we create a network using a different CIDR than the default? You can create a network with a different CIDR by specifying the **Gateway** and **Netmask** fields during network creation. ## Example By inputting: - **Gateway:** `10.1.2.1` - **Netmask:** `255.255.255.0` The system generates a network designated as `10.1.2.0/24`. This approach allows administrators to customize their network architecture beyond the default CIDR allocation, enabling flexible network design within the American Cloud platform. ## How is RDNS configured? RDNS is configured by us upon request. To enable it, we require KYC verification, including a government-issued ID, a bank statement showing the American Cloud charge, or other information to validate the customer. ## How to resolve IP conflicts when connecting to multiple networks with the same CIDR? You should create new networks with unique CIDRs to avoid IP overlap. The solution recommends redesigning network architecture to eliminate overlapping address spaces rather than attempting to bridge incompatible configurations. ## Is it possible to live-migrate a VM to a different region? Currently, it is not possible to live migrate a VM to a different region. You can create a backup of the VM and restore it to a different region. For detailed information on creating VM backups please review the following article: [American Cloud Backups](https://docs.americancloud.com/hc/docs/articles/1722537204-cloud-compute) ## Is it possible to scale Kubernetes workers vertically and add more CPU and RAM to a provisioned cluster? Vertical scaling is in our roadmap. As of today, it is not possible to vertically scale a cluster. Horizontal scaling is available by clicking the "Scale Kubernetes" button in the user interface and adding more workers. For more information on deploying Kubernetes applications please review: [American Cloud Kubernetes](https://docs.americancloud.com/hc/docs/articles/1722538069-kubernetes-_-getting-started) ## Is my bill paid automatically from my wallet balance, or do I need to add funds manually? You can either add funds to your wallet or keep a valid payment method on file. If a valid card is available, charges will be made automatically when your invoice is due. ## Is there support for integrating network-based storage solutions such as NFS, and if so, what is the recommended approach for provisioning and attaching such volumes within the cluster? We recommend Longhorn to accomplish PVCs: [https://longhorn.io/](https://longhorn.io/) If using PostgreSQL, please review the following article: [https://docs.percona.com/everest/index.html](https://docs.percona.com/everest/index.html) ## My card is repeatedly declined. I have tried to change the address multiple times, but it is still not working. If the main address is a P.O. Box, please make sure to use the secondary physical address configured for the credit card. ## What is the most efficient way to run a WordPress site with American Cloud? Setting up a compute instance (VM) and running WordPress from the marketplace is the preferred method. Please review the following articles on creating a new VM and running WordPress from the marketplace: [WordPress with Open LiteSpeed](https://docs.americancloud.com/hc/docs/articles/1722539363-wordpress-on-open-lite-speed) [Create VMs with American Cloud](https://docs.americancloud.com/hc/docs/articles/1722537204-cloud-compute) ## What’s the difference between ACE accounts and Public Cloud accounts? ACE (American Cloud Enterprise) accounts provide access to a private cloud with a separate interface and advanced infrastructure tools. They include API access and a Terraform provider. If you're interested, we’d be happy to schedule a demo. --- # Legal ## Acceptable Use Policy Content that does any of the following violates the American Cloud Acceptable Use Policy: - **Promotes violence:** The First Amendment creates a wide swath for free speech. But speech that is directed to inciting or producing imminent lawless action and is likely to incite or produce such action is not protected by the First Amendment. - **Infringes intellectual property rights:** Intellectual property rights are fundamental rights hardwired into the constitution and recognized as critical instruments for the promotion of science and creativity. Content that infringes or misappropriates intellectual property rights runs afoul of the American Cloud Acceptable Use Policy. - **Defames another:** Statements about an individual that are false and that harm the reputation of that individual are not constitutionally protected. Defamatory content violates the American Cloud Acceptable Use Policy. - **Facilitates human trafficking or illegal sex work:** Content that helps the trafficking of human beings as commodities, or that serves to enable other sorts of exploitative activities are contrary to the principles of individual liberty that guide American Cloud. - **Enables the sale of illegal goods:** American Cloud systems should not be used as a marketplace for the buying and selling of goods that would otherwise be illegal in the jurisdictions where the parties to the transaction reside. - **Inflicts psychological harm or invades privacy:** Certain content has the ability to wrongfully inflict devastating harm on others, and is not welcome on any American Cloud system. This includes revenge porn and other content that is intended primarily to injure another. - **Distributes harmful software:** Federal laws such as the Computer Fraud and Abuse Act serve to protect the private property interests of individuals and companies who engage in commerce and communications online. Using a American Cloud system to distribute technology that is destructive of these interests violates the American Cloud Acceptable Use Policy. - **Doxes another person:** Americans enjoy a First Amendment right to speak anonymously, particularly on matters of political or other societal concern. American Cloud will not aid any efforts to impede the exercise of this important right by permitting use of intimidating tactics to publicly identify individuals who wish to speak anonymously. - **Involves phishing, spamming or other unwanted or fraudulent communications:** These types of actions and communications are not protected by any free speech interest and only serve to detract from meaningful participation in the marketplace of ideas. American Cloud welcomes discussion about these Policies. Please feel free to send us an email at legal@americancloud.io Last updated: Oct 17, 2022. ## Services Agreement This legally binding Services Agreement (the "Agreement") is by and between American Cloud, LLC, a Delaware limited liability company with a registered address at 11 Church Rd., Ste. 1A, Hatfield, PA 19440 ("American Cloud") and the customer identified on the Order or other applicable Attachment that refers to this Agreement ("Customer"). This Agreement is effective as of the date on which Customer and American Cloud have both signed an Order or other applicable Attachment, or the date on which Customer first receives any Services, whichever is earlier (the "Effective Date"). By ordering the Services, Customer acknowledges and agrees that Customer has read, understands, acknowledges and agrees to be bound by all the provisions of this Agreement. The parties acknowledge receipt and sufficiency of good and valuable consideration and agree as follows: ## Definitions Capitalized words not elsewhere defined in this Agreement will have the following meanings: **"Account Information"** means any valid information, including billing information, contact information, payment information and such other information that Customer provides to American Cloud. **"Affiliate"** means any legal entity that owns, is owned by, or is commonly owned with a party. "Own" means having more than 50% ownership or the right to direct the management of the entity. **"American Cloud Parties"** means American Cloud and its subsidiaries, parents, Affiliates, shareholders, directors, officers, employees, agents, licensors, contractors, successors and assigns, and providers of Third-Party services, and those parties' respective subsidiaries, parents, Affiliates, shareholders, directors, officers, employees, agents, licensors, contractors, successors and assigns. **"American Cloud Portal"** means that set of online interfaces American Cloud or one of its Affiliates provides to Customer for purposes including but not limited to communication, billing, account management services and activities, etc. **"Attachment"** means any of the following, all of which are hereby incorporated by reference into this Agreement: (i) any electronic or hard copy document executed by the parties, including but not limited to any document made available and executed via the American Cloud Portal, that that refers or relates to this Agreement, (ii) any American Cloud-accepted written Order for the Services, and (iii) any document hyperlinked from within this Agreement. Capitalized words not otherwise defined within such Attachment will have the meanings of such words as defined in this Agreement. **"Billing Start Date"** means the date on which Fees first become due for the Services, as set forth in the applicable Attachment. **"Custom Deliverables"** means all materials developed specifically and exclusively for Customer by American Cloud, as set forth in an Order, in connection with Professional Services. **"Customer Data"** means all data, software and information, including, without limitation, data, text, software, scripts, video, sound, music, graphics and images that are uploaded or stored in connection with the Services by Customer or its Affiliates. **"Customer End User"** means a Third Party which is an end user of a Customer Offering. **"Customer Offering"** means any services provided by Customer to Third Parties, that directly utilize the Services. **"Customer Parties"** means Customer and its subsidiaries, parents, Affiliates, shareholders, directors, officers, employees, agents, licensors, contractors, successors and assigns. **"Due Date"** means the date on which Fees are due, initially established by the Billing Start Date, recurring each month as set forth in this Agreement, or pursuant to an applicable Attachment. **"Fees"** means those amounts due to American Cloud in exchange for the performance of the Services, as provided in an applicable Attachment. **"Implementation Start Date"** means the date on which American Cloud shall begin implementing Services (defined below) for Customer as set forth in an Order. **"Intellectual Property Rights"** means all inventions, patents, copyrights, trade secrets, trademarks, trade names, know-how, moral rights, and all other intangible proprietary or property rights, whether or not patentable (or otherwise subject to legally enforceable restrictions or protections against unauthorized third party usage), and any and all applications for, and extensions, divisions, and reissuances of, any of the foregoing, and rights therein, everywhere in the world, and whether arising by statute or common law. **"Order"** means a written document executed (including electronically) via both parties that sets forth the specific Services and any Deliverables to be provided, together with other commercial terms relating thereto, including but not limited to pricing, timelines and specific terms and conditions. **"Professional Services"** means migration, development, implementation, consulting and any other professional services that Customer may order, and American Cloud agrees to provide in accordance with an Order. **"Service Level Agreement" or "SLA"** means that service level agreement pertaining to the Services set forth at legal@americancloud.io. **"Services"** means those services American Cloud will provide to Customer as set forth in any Order or added by Customer in the future via any method, and includes Professional Services and Usage-Based Billed Services. **"Service Period"** means the period of time American Cloud will provide the Services to Customer as set forth in an applicable Attachment, such period to begin upon the Billing Start Date or a date otherwise agreed to in an Attachment. **"Site"** means any American Cloud data center location. **"SLA Credits"** mean the credits for applicable qualifying events as described in the Service Level Agreement. **"Third Party"** means any person or entity other than American Cloud or Customer, or such parties' Affiliates. **"Undisputed Fees"** means all Fees due under this Agreement except for those amounts for which Customer: (a) believes in good faith to be not due and owing, (b) designates in writing as "disputed" to American Cloud no less than 10 days prior to the Due Date, and (c) provides detail as to the basis of the disputed nature sufficient to enable American Cloud to propose and undertake a solution to the issue giving rise to the dispute. **"Usage-Based Billed Services"** means those Services provided under this Agreement that are billed on the basis of actual usage of the Services by Customer, the cost for which will be calculated by multiplying a fixed unit by a rate set forth in an applicable Attachment. **"Website"** means American Cloud.com or any successor website. ## Services American Cloud will provide the Services to Customer according to the specifications and timeframes set forth in the applicable Order, beginning on the Billing Start Date. Subject to Customer's compliance with the terms and conditions of this Agreement, American Cloud grants to Customer a nonexclusive, nontransferable, non-sublicensable, revocable right to access and use the Services for Customer's internal business purposes and to use the Services to create, offer and provide Customer Offerings. Customer will have sole responsibility to instruct American Cloud via the American Cloud Portal or another acceptable method to decommission, add, modify or remove any portion of the Services. Customer hereby grants to American Cloud a nonexclusive, royalty free, worldwide right and license to host Customer Data to the extent necessary for American Cloud to provide the Services to Customer under this Agreement. ## Fees and Payment Customer will pay American Cloud the Fees for the Services in the amounts and otherwise as set forth in the applicable Attachment. Customer will pay the Fees to American Cloud no later than the Due Date, each month, in U.S. Dollars. Any portion of Fees remaining unpaid 1 day or more beyond the Due Date will be subject to interest of 1.5% per month or the maximum permitted by law, whichever is less. Usage-Based Billed Services identified as such in an applicable Attachment will be billed on the basis of consumption and in intervals set forth in an applicable Attachment. Each unit of a Usage-Based Billed Service consumed by Customer will be rounded up to the next whole unit. A base rate and overage rate for the Services may be established by American Cloud and communicated to Customer in an applicable Attachment. Customer will be responsible for the tracking and controlling of its usage of the Usage-Based Billed Services from within the American Cloud Portal, and American Cloud will have no responsibility to notify Customer pertaining to any usage. Professional Services will be provided on an hourly basis and billed in 15-minute intervals at American Cloud's then current rates or otherwise as agreed by the parties. Professional services provided for purposes of onboarding (including but not limited to data migration from other providers, configuration of servers, and other tasks directly related to "moving in") will be billed at a flat one-time rate agreed upon by the parties in advance and set forth in an Order. Customer will pay all Fees using a payment method that is maintained on file with American Cloud, such as, but not limited to, credit card, ACH electronic funds transfer, or such other method as approved by American Cloud. Customer will be responsible for all fees, including processing fees, associated with making payment via wire transfer to American Cloud. Returned electronic check payments will be subject to a returned check fee of $25.00 or the highest amount permitted by law, whichever is lower. Customer is responsible for any fees and costs (including, but not limited to, reasonable actual attorney's fees, court costs and collection agency fees) incurred by American Cloud in enforcing collection of Fees. Customer hereby authorizes American Cloud to automatically charge Customer's payment method on file with American Cloud on or before the applicable Due Date. If Customer's payment method is a physical check or money order, Customer authorizes American Cloud to use information from the check to make a one-time electronic transfer from Customer's account as soon as the same day Customer makes payment, in which case Customer may not receive the check back from its financial institution. Customer will pay or provide appropriate exemption documentation for all taxes, duties, levies, and any other fees (except for taxes based upon American Cloud's net income) related to the Services imposed by any governmental authority. All Fees are exclusive of any such taxes, duties, levies, or fees. In the event that American Cloud suspends or terminates any portion of the Services due to cause, such as non-payment of Fees, or other violations of this Agreement (including but not limited to violations of the American Cloud Community Policies), as authorized under this Agreement, American Cloud may, as a condition for restoring the Services, require that Customer pay to American Cloud, in advance, a reasonable reconnection fee to defray American Cloud's reasonable administrative and similar costs to restore the Services to Customer. The payment of such reconnection fee will be in addition to any Fees remaining due and owing to American Cloud. All Fees are nonrefundable. Customer's sole remedy for American Cloud's nonperformance of any Services will be a credit issued in accordance with any applicable Service Level Agreement. American Cloud may adjust the Fees in proportion with any increase in or changes to Third Party costs which are directly related to providing the Services to Customer, provided that (a) such increase or change is not due to any action initiated by American Cloud, and (b) American Cloud is unable to procure at more favorable prices alternative, comparable (as determined in American Cloud's discretion) Third Party products despite American Cloud's commercially reasonable efforts to do so. American Cloud may adjust its software offering and associated Fees in accordance with Third Party vendor program releases, policies or requirements. American Cloud will provide at least 30 days' prior notice to Customer of any increase in or changes to Third Party Costs under this subsection. ## Term This Agreement will begin on the Effective Date, and unless terminated earlier as permitted under this Agreement, will continue in effect until the completion of all Services as set forth in all applicable Attachments. Service Periods will be set forth in the applicable Attachment. If the Implementation Start Date is delayed due to Customer action or inaction, American Cloud may establish a new Implementation Start Date up to 15 days later than the initial Implementation Start Date, provided that any Customer action or inaction does not (i) make such new Implementation Start Date impracticable, or (ii) make American Cloud's efforts at addressing the issue in response to any Customer action or inaction commercially unfeasible. American Cloud may, at American Cloud's sole discretion, extend the Service Period by the number of days by which the Implementation Start Date is delayed. Customer may request additional Services during the term of this Agreement by submitting the appropriate written Order form for such Services. The Service Period for each such new Service will be set forth in the Order. ## Suspension and Termination American Cloud acknowledges that the discontinuation of Services is a drastic remedy that impacts the freedom of information to be transmitted and shared. Accordingly, American Cloud has adopted the provisions of this section relating to suspension and termination to narrowly address circumstances where such suspension is necessary to protect the legitimate and lawful interests of American Cloud, other customers, and the general public interest in a free and open internet. American Cloud may suspend the Services if Customer is in material breach of any provision of this Agreement (including nonpayment of any Undisputed Fees) and such breach has not been cured to American Cloud's reasonable satisfaction within 14 days' written notice to Customer. Prior notice of suspension will not be required if American Cloud determines, in its reasonable discretion, that suspension is necessary to protect American Cloud, its providers, or its other customers from operational, security, or other material risk, or if the suspension is ordered by a court or other tribunal. In the event of suspension, Customer will remain liable for all Fees that would have been paid had the Services not been suspended. Either party may terminate this Agreement or the Services under an applicable Attachment for material breach (including nonpayment of any Undisputed Fees) as provided in this subsection. If this Agreement or an applicable Attachment provides for Customer to receive the Services on a month-to-month basis, either party may terminate for material breach, provided that the nonbreaching party has given the other party written notice of and the opportunity to cure the breach, and such breach has not been cured within 10 days of the notice. If this Agreement or an applicable Attachment provides for Customer to receive the Services on terms longer than a month-to-month basis, either party may terminate for material breach, provided that the nonbreaching party has given the other party written notice of and the opportunity to cure the breach, and such breach has not been cured within 30 days of the notice. Termination for breach will not alter or affect either party's right to seek any available remedy. Except for termination as provided in this Section due to American Cloud's material breach, in the event Customer seeks to terminate this Agreement or an applicable Attachment prior to expiration, Customer will be liable for all Fees due during the remainder of the Service Periods of all applicable Services, and such Fees will become immediately due and payable without further notice or demand from American Cloud. ## Post Termination Obligations and Procedures Upon expiration or termination of this Agreement or, as applicable, an Attachment: Customer will discontinue use of the Services and relinquish use of the IP addresses and server names assigned to Customer by American Cloud and any other materials provided to Customer by American Cloud in connection with the Services, including pointing the DNS for Customer domain name(s) away from the Services; and all licenses granted to Customer, and all rights of Customer to receive the Services, will terminate. American Cloud will have no obligation to provide any transition services or access to data except as expressly provided in this Agreement or as otherwise agreed in writing by the parties and as set forth in an applicable Attachment. Provided that Customer has paid all Undisputed Fees and is not otherwise in material breach under this Agreement, for a period of 7 days following the effective termination or expiration of this Agreement or applicable Attachment, American Cloud will permit Customer to copy Customer Data from American Cloud's system. After such time, American Cloud will have no obligation to retain any Customer Data and may freely delete such Customer Data without liability to Customer. For purposes of clarity, nothing in this Agreement will impair American Cloud's right and ability to immediately and permanently delete any Customer Data or other content that violates the American Cloud's Acceptable Use Policy set forth at americancloud.com/legal#AUP. Any obligations and duties which by their nature extend beyond the expiration or termination of this Agreement will survive the expiration or termination of this Agreement. Without limiting the generality of the foregoing, Sections 1, 5, 6, 13, 15, 16, 18 and 23 will survive the expiration or termination of this Agreement. ## User Control Considerations Customer will (a) delegate access to Customer employees via the American Cloud Portal, (b) assign and maintain a secure authentication mechanism to control access to sensitive information, including but not limited to, Customer passwords, (c) maintain and change passwords frequently, and promptly upon providing access to American Cloud or any Third Party to perform maintenance activities on Customer's behalf, and (d) provide to American Cloud a primary notification point of contact to serve as Customer's authorized representative to make technical and financial decisions. ## Service Levels American Cloud will provide the Services in accordance with the Service Level Agreement set forth at americancloud.com/legal#SLA. American Cloud will provide SLA Credits according to the terms of the applicable Service Level Agreement. Credits under the Service Level Agreement, if issued to Customer's account, will be used only to offset future Fees for certain Services as provided in the Service Level Agreement. Such credits may not be sold, converted to cash, used to pay past due balances, or transferred to any Third Party or Affiliate, and will expire on the termination or expiration of this Agreement. American Cloud may provide support services via the American Cloud Portal or other means as it determines from time to time. American Cloud may close or put on hold any request for service if Customer has not updated such request for 72 hours after notification from American Cloud. ## Subcontractors American Cloud may use one or more subcontractors to provide the Services or a portion of the Services. Unless otherwise agreed in writing, American Cloud will be solely responsible for any fees or charges incurred through use of subcontractors to the extent required to provide the Services, and subcontracting will not increase the Fees payable under this Agreement. Customer will pay any fees for subcontractors that American Cloud may retain to provide agreed upon services in excess of the scope of the Services set forth in this Agreement. ## Backup and Security Except for responsibility for reasonable physical security of the servers and related hardware used to provide the Services, and except as expressly provided in an applicable Attachment, Customer will be solely responsible for data maintenance, integrity, retention, security, business continuity, disaster recovery and backup of Customer Data. Customer has the option to contract with American Cloud for the services listed in the preceding sentence, or related services. Customer will use reasonable security precautions for providing access to the Services by its employees or other individuals to whom it provides access, whether in connection with Customer's internal business purposes or as a Customer Offering. Customer will be solely responsible for ensuring the confidentiality and security of all account usernames and passwords, and for all user conduct in connection with such account credentials. Customer will implement internal protocols and procedures whereby terminated personnel will no longer be able to use any Customer username or password. All passwords used by Customer, or its personnel must be smart, secure combinations of characters and not be comprised solely of dictionary words. American Cloud will comply with all applicable laws pertaining to data breach and notification of same. Customer shall promptly notify American Cloud of any potential, suspected or actual security breach concerning the Services or Customer Data about which Customer becomes aware. ## Client Consent to Monitor American Cloud, LLC (AC) uses monitoring software to track usage information. By agreeing to this services agreement, you acknowledge and consent that when you access an AC information system (IS): - All communications and data transiting, traveling to or from, or stored on this IS will be monitored. - You consent to the unrestricted monitoring, interception, recording, and searching of all communications and data transiting, traveling to or from, or stored on this system at any time and for any purpose by AC and by any person or entity, including government entities, authorized by AC. - You consent to the unrestricted disclosure of all communications and data transiting, traveling to or from, or stored on this system at any time and for any purpose to any person or entity, including government entities, authorized by AC. - You are acknowledging that you have no reasonable expectation of privacy regarding your use of this IS. - These acknowledgments and consents cover all use of the IS, including work-related use and personal use without exception. ## Customer's Obligations Customer will comply, and will require its Customer End Users comply, with American Cloud's Acceptable Use Policy available at americancloud.com/legal#AUP and will not otherwise use the Services for any unlawful purpose. Customer will provide reasonable cooperation with American Cloud to investigate any violation of this provision. Customer will promptly remove or disable access to any content alleged to infringe the copyright of any third party, and otherwise comply with all other requirements of the safe harbor provisions of the Digital Millennium Copyright Act ("DMCA"), found at 17 U.S.C. §512, as amended from time to time. The obligations of Customer to comply with DMCA takedown notices applies regardless of whether Customer has received a takedown notice directly from a third party, or has received a forwarded takedown notice from American Cloud. Without limiting any other provision in this Agreement, Customer agrees that any repeated failure to promptly disable access to or delete content alleged to infringe copyright is a material breach of this Agreement, and American Cloud may immediately terminate this Agreement or take other reasonably necessary actions to ensure that no further infringements will occur. For the term of this Agreement and for the period of twelve (12) months thereafter, without the prior written consent of the other party, neither party shall either directly or indirectly solicit or entice away (or seek or attempt to entice away) from the employment of the other party any person employed (or any person who has been so employed in the preceding six (6) months) by such other party in the provision or receipt of the Services. Customer agrees to do each of the following: (a) cooperate with American Cloud's investigation of outages, security problems, and any suspected breach of this Agreement; (b) reasonably cooperate with any lawful and valid law enforcement investigation (including, but not limited to providing appropriate responses to or arguments against subpoenas or court orders relating to Customer's or Customer End User's conduct); (c) comply with all license terms or terms of use for any software, content, service or website (including Customer Data) which Customer uses or accesses when using the Services; (d) give American Cloud true, accurate, current, and complete Account Information; (e) keep Customer's Account Information up to date; (f) be responsible for the use of the Services by Customer and Customer End Users and any other person to whom Customer has given access to the Customer Offering; (g) use commercially reasonable efforts to prevent unauthorized access to or use of the Services; and (h) where the Customer provides a Customer Offering as permitted under this Agreement, enter into an agreements with Customer's End Users containing relevant terms of this Agreement and releasing American Cloud from any and all liability for damages or losses Customer End Users may incur as a result of using the Customer Offering. Customer will not copy, transfer, reverse engineer, disassemble, decompile, create derivative works of, or, except as part of an authorized Customer Offering, allow Third Party access to the Services. Customer will not remove any proprietary notices or labels contained in or placed by the Services and will not use, post, transmit, or introduce any device, software, or routine which interferes or attempts to interfere with the operation of the Services. Customer will not take any action that imposes an unreasonable or disproportionately large load on the infrastructure of the Services' systems or networks, or any systems or networks connected to the Services. Customer will reasonably comply with any request by American Cloud to cooperate in connection with any third-party audit, including but not limited to software audits. ## IP Allocation Customer acknowledges and agrees that the use of IP addresses in a manner not authorized under this section does not affirm the important free speech and other interests set forth in the American Cloud Community Policies. ### IP Addresses Assignment of an American Cloud IP (Internet Protocol) address to Customer, either IPv4 or IPv6, does not constitute transfer of ownership, as the IP address will continue to be owned by American Cloud, licensed to Customer for use in accordance with the terms and conditions of this Agreement. American Cloud will use commercially reasonable efforts to ensure that the IP addresses allocated to Customer remain allocated to Customer. However, American Cloud reserves the right to change IP address allocations for any reason (including, but not limited to upgrades, security provisioning, or other network migration service). American Cloud will use commercially reasonable efforts to provide Customer with advance notice of IP address changes. ### Obligation to Preserve the Good Standing of American Cloud IPs and Not to Manipulate IP Addresses If Customer is assigned any of American Cloud's IP addresses (IPv4 and/or IPv6), Customer agrees to maintain the integrity and industry good-standing of American Cloud's IP addresses and not to undertake any actions that might cause American Cloud's mail servers or any of its IP addresses or ranges to be placed on any "blacklist" or "black hole list" (e.g., www.spamhaus.org, "XBL," or "SBL") or any other mail filtering software systems used by companies on the internet. Customer agrees to notify American Cloud immediately if Customer learns that any of American Cloud's IP addresses have been placed on any such list. Customer agrees to take whatever steps are necessary (or fully cooperate with American Cloud in taking whatever actions it deems necessary) to remove any of American Cloud's IP addresses from any such lists immediately. Customer agrees to not modify any configuration that will conflict with, or disrupt American Cloud's network services. Customer acknowledges and agrees that American Cloud information may be associated with Customer's servers' IP addresses as Customer's webhosting provider on WHOIS and other webhost lookup/search tools. ## Indemnification Each party recognizes, in the spirit of the American Cloud Community Policies, that it has a responsibility concerning its own actions, and accordingly, the parties agree in this section to allocate the risks arising from the others' conduct in a reasonable manner. Customer will defend, indemnify, and hold the American Cloud Parties harmless from and against all Claims, whether or not suit is filed, arising out of, resulting from or connected with, in whole or in part: (i) Customer's use of the Services or Third Party services; (ii) any infringement or alleged infringement by the Customer Data of any Third Party Intellectual Property Right, (iii) any breach or alleged breach by Customer of this Agreement, including any warranty contained in this Agreement; (iv) any violation or alleged violation by Customer or Customer End Users of a Third Party's rights, including, without limitation, any actual or alleged infringement or misappropriation of a Third Party's copyright, trade secret, patent, trademark, privacy, right of publicity or other proprietary right; (v) any damage caused by or alleged to have been caused by Customer or Customer End Users to the Site or Services; (vi) any actual or alleged violation or noncompliance by Customer or Customer End Users with any applicable law, court order, rule or regulation in any jurisdiction; or (vii) as applicable, Customer's resale of the Services. ## Warranties Each party represents and warrants to the other that it is a business entity duly organized, that it has all rights necessary to enter into this Agreement, and that by entering into this Agreement it will not be in breach of any other agreement or obligation. American Cloud warrants that the Services will be provided in a diligent and skillful manner in accordance with reasonable industry standards. Customer warrants and represents that (a) its use of the Services will comply with and be in accordance with all applicable laws and regulations, including but not limited to all laws and regulations specifically addressing Customer's industry, and (b) that the Customer Data will not infringe or misappropriate the Intellectual Property Rights or other rights of any Third Party. ## Disclaimer of Warranties Except for the warranties set forth above, which are limited warranties and the only warranties provided by American Cloud Parties to Customer, the Services are provided "AS IS," and American Cloud Parties make no additional warranties, express, implied, arising from course of dealing or usage of trade, or statutory, as to the Services or any matter whatsoever. American Cloud Parties disclaim all implied warranties of merchantability, fitness for a particular purpose, satisfactory quality, title and non-infringement. American Cloud Parties do not warrant that the Services will meet any Customer requirements not set forth in this Agreement, that the Services will be uninterrupted or error-free, or that all errors will be corrected. ## Limitation of Liability IN NO EVENT SHALL AMERICAN CLOUD PARTIES, BE LIABLE TO CUSTOMER OR ANY OTHER PERSON OR ENTITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES WHATSOEVER WHETHER BASED ON WARRANTY, CONTRACT, TORT, OR ANY OTHER LEGAL OR EQUITABLE THEORY, (INCLUDING FOR LOSS OF PROFITS, SAVINGS, REVENUE, OR USE, DAMAGED OR LOST FILES OR DATA, OR BUSINESS INTERRUPTION) THAT MAY ARISE IN CONNECTION WITH THIS AGREEMENT, ANY SERVICES PROVIDED TO CUSTOMER, OR ANY MATTER WHATSOEVER, REGARDLESS OF THE CAUSE OF ACTION OR CHARACTERIZATION OF THE DAMAGES, EVEN IF THE PARTY SOUGHT TO BE HELD LIABLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ADDITION, CUSTOMER SPECIFICALLY ACKNOWLEDGES AND AGREE THAT IN NO EVENT SHALL AMERICAN CLOUD'S TOTAL AGGREGATE LIABILITY EXCEED THE AMOUNT OF FEES PAID BY CUSTOMER UNDER THIS AGREEMENT DURING THE 12-MONTH PERIOD PRECEDING THE FIRST ACT GIVING RISE TO LIABILITY. THE FOREGOING LIMITATION OF LIABILITY SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY LAW, AND SHALL SURVIVE ANY TERMINATION OR EXPIRATION OF THIS AGREEMENT OR YOUR USE OF THE SERVICES. ## Essential Basis of Bargain Customer acknowledges that the Fees reflect the overall allocation of risk between the parties, including by means of the provisions for limitation of liability and exclusive remedies described in this Agreement. Such provisions form an essential basis of the bargain between the parties and a modification of such provisions would affect substantially the Fees charged by American Cloud. In consideration of such Fees, Customer agrees to such allocation of risk and hereby waives any and all rights, through equitable relief or otherwise, to subsequently seek a modification of such provisions or allocation of risk. ## Confidentiality Each party agrees that information relating to the other that is known to be confidential or proprietary, or which is clearly marked as such, will be held in confidence and will not be disclosed or used except to the extent that such disclosure or use is necessary to the performance of the Services. The obligations of confidentiality in this Section will not apply with respect to information that is independently developed by either party, lawfully becomes a part of the public domain, or of which the other party gained knowledge or possession free of any confidentiality obligation. American Cloud may disclose information, including information that Customer, or Customer End Users, may consider confidential, in order to comply with a court order, subpoena, summons, discovery request, warrant, regulation, or governmental request. ## Export Customer will comply with all applicable export laws and regulations of the United States of America, and assure that its use of the Services will not result in (a) export, directly or indirectly, in violation of any applicable export laws; or (b) any use or purpose prohibited by applicable export laws, including nuclear, chemical, or biological weapons proliferation. The parties will not take any actions that would cause either party to violate the U.S. Foreign Corrupt Practices Act of 1997, as amended. ## Intellectual Property Rights As between the parties, American Cloud retains all right, title and interest in and to the software and systems used to provide the Services. For purposes of clarity, as between American Cloud and Customer, American Cloud shall retain all Intellectual Property Rights associated with or embodied within the Services. Customer acknowledges that Third Party software may be embedded or otherwise delivered as part of the Services. Customer may only use such Third-Party software as integrated with and part of the Services. The licensors of the Third-Party software are intended beneficiaries of this Agreement, as it pertains to Customer's rights to use such software. American Cloud reserves all rights in the Services which it has not expressly granted to Customer under this Agreement, and Customer agrees to not assert any implied rights to use or otherwise exercise any rights in any American Cloud system or software. Customer hereby grants to American Cloud a nonexclusive, worldwide, royalty-free, fully paid-up license during the term to use Customer's trademarks, marks, logos or trade names in connection with American Cloud's provision of Services (including support of Services) to Customer and to be listed as an American Cloud customer on the Website and in other marketing or promotional materials. ## Custom Deliverables Unless otherwise set forth in an applicable Attachment, Customer will own the Custom Deliverables, if any, and such Custom Deliverables will be considered a work made for hire. To the extent the Custom Deliverables cannot be considered a work made for hire, American Cloud hereby assigns to Customer its entire right, title and interest, including all Intellectual Property Rights, in the Work Product. American Cloud shall retain all right, title and interest, including all Intellectual Property Rights embodied within or associated with American Cloud's Background Technology. "Background Technology" means any materials, technologies, know-how or the like created or developed by or for American Cloud, or acquired by American Cloud (including materials and technology available to American Cloud in accordance with a license grant) either (i) prior to the Effective Date of this Agreement, (ii) subsequent to such Effective Date if conceived, reduced to practice, authored, created or developed separately and independently of American Cloud's performance under this Agreement, or (iii) of general utility to American Cloud in the performance of services in the marketplace. ## Press Releases and Publicity After execution of this Agreement, the parties may issue a joint press release announcing the parties' relationship under this Agreement. The timing and content of any press release will be subject to the approval of each party, which approval may not be unreasonably withheld, conditioned or delayed. American Cloud may, however, identify Customer as a customer of American Cloud in marketing, promotion and other public communications. Except as required by law, and as permitted under this Section, neither party will make any public statements, press releases or other public announcements regarding the parties' relationship without the prior written approval of the other party, and neither party may use the other party's trademarks or company name. ## General Provisions ### Force Majeure With the exception of Customer's payment obligations, neither party will be responsible for delays or failures in performance resulting from acts of God, acts of civil or military authority, fire, flood, strikes, war, terrorism, epidemics, pandemics, shortage of power, telecommunications or internet service interruptions or other acts or causes reasonably beyond the control of that party. ### Governing Law and Dispute Resolution This Agreement will be governed in all respects by the laws of the Commonwealth of Pennsylvania without regard to conflict of law provisions. Any dispute arising under this Agreement will be subject to binding arbitration by a single arbitrator with the American Arbitration Association (AAA), in accordance with its relevant industry rules, if any. The arbitration will be held in Doylestown, Pennsylvania. The arbitrator will have the authority to grant injunctive relief and specific performance to enforce the terms of this Agreement. Judgment on any award rendered by the arbitrator may be entered in any court of competent jurisdiction. ### Compliance With Laws Each party will comply with all applicable federal, state and local laws and regulations. If, after the Effective Date of this Agreement any law becomes effective which substantially and materially alters the ability or cost of either party to perform its obligations under this Agreement in whole or part, the parties will renegotiate the provisions of this Agreement to the extent necessary to reflect the effect of such law. If renegotiations do not result in terms agreeable to both parties, the party that would bear the altered cost due to the change in the law will have the right to terminate this Agreement without penalty upon thirty (30) days' written notice to the other party. ### Limitations of Actions No action, regardless of form or substance, arising out of this Agreement or the performance or nonperformance of any of the parties' obligations hereunder may be brought more than one (1) year after a party knew or should have known of the occurrence of the event giving rise to such cause of action. ### Assignment Neither party will assign or transfer any rights or obligations under this Agreement (including by operation of law or otherwise) without the prior written consent of the other party. Notwithstanding the preceding sentence, with the exception of an assignment to a competitor of the non-assigning party (which will require consent from the non-assigning party), either party may assign this Agreement without obtaining the consent of the other party, to an entity into which the assigning party is merged, or to an acquirer of all or substantially all of the business or assets of the assigning party, or as part of a business restructuring, sale of stock, or other recapitalization or reorganization. Any purported assignment of rights or transfer of obligations in violation of this section is void. This Agreement will bind each party's authorized successors and assigns. ### No Third-Party Beneficiaries Nothing expressed or implied in this Agreement is intended to confer upon any person other than the parties and their respective successors or permitted assigns, any rights, remedies, obligations or liabilities whatsoever. ### No Waiver The waiver by either party of any breach of this Agreement will not be construed to be a waiver of any succeeding breach. All waivers must be in writing, and signed by the party waiving its rights. ### Notices Any notice required under this Agreement shall be provided to the other party in writing. Any notice from Customer to American Cloud must be delivered personally or sent by nationally recognized overnight courier or by certified mail, postage prepaid, return receipt requested, to: American Cloud, Attn: Legal Dept., 11 Church Rd., Ste. 1A, Hatfield, PA 19440. American Cloud may give general notices concerning the Services to Customer by means of a notice on the American Cloud Portal, and notices specific to Customer by electronic mail to the Customer e-mail address in American Cloud's account records for Customer, or delivered personally or sent by nationally-recognized overnight courier or by certified mail, postage prepaid, return receipt requested to the Customer address on record in American Cloud's account records. ### Relation of the Parties The parties agree they are acting as independent contractors and under no circumstances will any of the employees of one party be deemed the employees of the other for any purpose. Except as otherwise expressly agreed by the parties, this Agreement will not be construed as authority for either party to act for the other party in any agency or other capacity, or to make commitments of any kind for the account of or on behalf of the other. Nothing in this Agreement will be deemed to constitute a joint venture or partnership between the parties. ### Severability If any provision of this Agreement is found to be unenforceable or contrary to law, it will be modified to the least extent necessary to make it enforceable, and the remaining provisions of this Agreement will remain in full force and effect. ### Pronouns Unless otherwise stated in this Agreement, a reference to the singular includes the plural and vice versa. ### Order of Precedence The parties hereby incorporate all Attachments into this Agreement by reference. In the event of inconsistency between any Attachment and this Agreement, unless the Attachment expressly provides that it prevails, the relevant provisions of this Agreement will prevail. ### Headings Headings and titles used in this Agreement are for convenience only and do not form a part of this Agreement. ### Entire Agreement This Agreement constitutes the entire agreement between the parties with respect to its subject matter, and supersedes all other agreements (express or implied), proposals, negotiations, representations or communications relating to the subject matter. Both parties acknowledge that they have not been induced to enter this Agreement by any representations or promises not specifically stated in this Agreement. The protections of this Agreement will apply to actions of the parties performed in preparation for and anticipation of the execution of this Agreement. Acceptance of any Order by American Cloud is made upon the express understanding that it will be governed by the terms and conditions of this Agreement only and that any additional, conflicting, or inconsistent terms and conditions which may appear in any Order provided by Customer will be void and have no force and effect notwithstanding any acceptance or execution by American Cloud. Any amendment to this Agreement must be in writing and signed by duly authorized representatives of the parties. Last updated: Oct 17, 2022. ## Privacy Policy This Privacy Policy describes how American Cloud Inc. and its affiliates (collectively, "American Cloud," "we," "our" or "us") collect and use Personal Data in relation to the American Cloud websites, products, applications, and similar services (collectively, the "Services") that link to this Privacy Policy. We take the privacy, security and confidentiality of your information, including any data collected that could directly or indirectly identify you ("Personal Data") seriously. We want you to be aware of how we use your Personal Data, and how to update or correct your information if necessary. This Privacy Policy is for you. Please read it carefully. BY ACCESSING THE SITES, CREATING A AMERICAN CLOUD ACCOUNT, OR USING OUR SERVICES, YOU ARE CONSENTING TO THE COLLECTION, USE, DISCLOSURE, TRANSFER, AND STORAGE OF PERSONAL AND NON-PERSONAL DATA OR OTHER INFORMATION RECEIVED BY US AS A RESULT OF SUCH USE IN ACCORDANCE WITH THIS PRIVACY POLICY. Please note that this Privacy Policy does not apply to any of the data or content processed, stored or hosted by American Cloud customers by or through a customer account. Please see the American Cloud services agreement set forth at americancloud.com/legal#SA for information regarding the same. ## Information That We Collect ### Information that You Provide Directly We collect the following types of information that you provide directly when you establish an account, use our Services, for promotional purposes, and in connection with certain online surveys or sweepstakes that we sponsor: name, email address, billing and/or mailing address, telephone number, zip code, date of birth, and other, similar types of data. This information will be used to keep you updated about our Services and any of the American Cloud agreements which are applicable to the products or services you have purchased or to which you have subscribed, and to keep you informed about special offers, sales or new features of the Services that we think may be of interest to you. In the event that you are purchasing extensions, such as domain names, we may require additional supporting documentation, including driver's license number, passport number, and similar. We do not store or otherwise use this information except in connection with the same. ### Information that We Collect Automatically We automatically collect site usage information which includes, without limitation, Internet Protocol ("IP") address(es), browser information, other characteristics of your device and software, domain names of your Internet Service Provider, your approximate geographic location, the time of your usage and certain aggregated use data. This information is used to analyze the use of, and to improve our Services (including to help diagnose and prevent problems with our servers or our products or services), to administer American Cloud and more generally to provide our customers with the best possible user experience. Like many online providers, American Cloud uses a technology called "cookies" to collect some of this data. A cookie is a piece of information that is placed on your browser when you access a site. In many cases, the information collected using cookies (and related technologies) is used in non-identifiable ways. For example, we use information we collect about users to optimize our sites and to understand traffic and usage patterns. In other cases, we associate the information we collect using cookies and related technologies in a manner that may directly or indirectly identify you, and in such cases treat it as Personal Data. Additionally, if the settings on your location-aware device allow us to receive geo-location data or information, we may collect that information automatically. We also use tracking information to determine which areas of our site users visit most frequently. American Cloud does not track what individual users read, but rather how often each page is visited. Cookies help provide additional functionality to the sites and help us to more accurately analyze usage of the sites. For instance, the sites may set a cookie on your browser that allows you to more quickly access the sites during future visits. We use cookies to monitor and to maintain information about your use of the sites. Cookies are also used to track the identity of the website you visited immediately prior to visiting any of our sites. We do not otherwise track information about your use of other websites. Cookies also allow us to hold selections in a shopping cart when a user leaves the sites without checking out. Cookies are not used on the sites to store your account information as this information is stored securely on a server. When you log in at the sites with your username and password, we will assign you a secure session id. The server then passes your information to you through this secure session id. Cookies may be session cookies (i.e., last only for one browser session) or persistent cookies (i.e., continue in your browser until they are deleted or expire). Some of the cookies we use may be flash cookies or Adobe cookies. While they are harmless, they may contain demographic information and depending on your browser these cookies may not normally be deleted when your cookies are deleted. Please check your browser to determine where these types of cookies are stored and how they may be deleted. In some countries, including countries in the European Economic Area ("EEA"), these sorts of cookie data may be considered Personal Data under applicable data protection laws. While we recommend that you leave cookies turned on as they allow you to take advantage of some of the features of the sites, you have the ability to control the use and moderation of our cookies. However, if you elect not to allow cookies to be placed as provided herein, you may not be able to use or to enjoy all of the services and features of the sites. Specifically, you can configure the settings (i) to receive notifications when you are receiving new cookies, (ii) to disable cookies or (iii) to delete cookies. Please refer to your browser's help section for information on how to do this. We also use analytics providers, to collect certain information about our users and the use of our sites more generally. ### Information that Third Parties Provide About You We may also receive information about you from third parties. For example, if you are on another website that provides information about service providers like American Cloud and you request to receive information from American Cloud, that website will forward your contact and other information to us so that we may contact you as requested. Third parties may also provide information about you in connection with a marketing arrangement we may have with those third parties. We may supplement the information we collect with outside records from third parties in order to provide you with the information, goods, or services you have requested to enhance our ability to serve you and to offer you opportunities to purchase products or services that we believe may be of interest to you. We may combine the information we receive from those other outside sources with information we collect through our Services. In those cases, we will apply this Privacy Policy to the combined information. ### Do Not Track Please note that American Cloud does not support "Do Not Track" browser settings and we do not currently participate in any "Do Not Track" frameworks that would allow us to respond to signals or other mechanisms from you regarding the collection of your personal or non-personal identifying information. ## How We Use Your Information We use your Personal Data and other information as necessary to provide our Services, including to make ongoing improvements. We may also use your Personal Data for internal business purposes including, without limitation, to help us improve the content and functionality of the Services, to better understand our users and the ways in which they use the sites and Services to protect against, identify or address fraudulent activities, to manage your account, and to provide you with customer service and to generally manage the Services and our business. Finally, we may use your Personal Data to contact you for certain marketing and advertising purposes, including, without limitation, to inform you about our offers, contests or surveys which may be of interest to you and to display content and advertising on or off the sites regarding our Services which may be of relevance to you. ## Sharing Your Information American Cloud is not in the business of selling your Personal Data. We do not share, sell or rent any of the Personal Data provided to use through our sites or the Services to third parties, except as expressly described in this Privacy Policy. Instances in which we may share your Personal Data include: **With Service Providers:** We, like many businesses, sometimes engage other companies to perform certain business-related functions on our behalf so that we can focus on our core business. Examples of these services include, but are not limited to, payment processing and authorization, fraud protection and credit risk reduction, product customization, order fulfillment and shipping, marketing and promotional material distribution, website evaluation, social media management, data analysis and, where applicable, data cleansing. In connection with services those partners provide for us, we may provide or otherwise give them access to certain Personal Data, but their access to and use of this information is strictly limited to the purposes of providing these specific services to American Cloud. **For Business Transfers:** As with any business, it is possible that as our business develops, we might sell, assign, buy, transfer or otherwise acquire or dispose of certain businesses or corporate assets. In any such event, Personal Data may be part of the transferred assets. You acknowledge and agree that any successor to or acquirer of us will continue to have the right to use your Personal Data and other information in accordance with the terms of this Privacy Policy. **With Parents, Subsidiaries and Affiliates:** We may also share your Personal Data with our parent company, future subsidiaries and/or affiliates consistent with this Privacy Policy. Our future subsidiaries and affiliates will be bound to treat and to maintain any Personal Data in accordance with this Privacy Policy. **Legal Requirements:** We may disclose your Personal Data if required to do so by law (including, without limitation responding to a subpoena or request from law enforcement, court or government agency or other public authorities) or in the good faith belief that such action is necessary (i) to comply with a legal obligation, (ii) to protect or defend our rights, interests or property or that of other customers or users, (iii) to act in urgent circumstances to protect the personal safety of users of the Services or the public, or (iv) to protect against legal liability or potential fraud, as determined in our sole discretion. **With Your Consent:** If we intend to use any Personal Data in any manner that is not specified herein, we will inform you of such anticipated use prior to or at the time at which the Personal Data is collected or we will obtain your consent subsequent to such collection but prior to such use. In short, we will honor the choices you make regarding your Personal Data and will inform you about any other intended uses of such information. ## Changing Your Information; Updating Your Personal Data For information and Personal Data that we have collected on your behalf, we will grant you reasonable access to the same as required by applicable law. If you have established an American Cloud Account, we rely on you to keep the information on record updated and accurate. Our Services allow you to modify or delete your Account information at your discretion. If any of our Services do not permit you to update or modify your information, please contact us as set forth herein below to request assistance with the same. Note that we may keep historical information in our backup files as permitted by law. ## Employment Applications If you apply for employment with American Cloud through our sites, we, or a third party providing human resources assistance, may ask you to provide self-identifying information (such as veteran status, gender, and ethnicity) in conjunction with laws and regulations enforced by the Equal Employment Opportunity Commission ("EEOC"), the Office of Federal Contract Compliance Programs ("OFCCP"), and similar state and local regulatory agencies. Providing self-identifying information is voluntary, but if you do provide us with that information, we may submit it to the EEOC, the OFCCP, and similar state and local regulatory agencies for business-related purposes, including responding to information requests, fulfilling regulatory reporting requirements, and defending against employment related complaints. Otherwise, any information submitted as a part of the employment process will be treated in accordance with this Privacy Policy. ## Third Party Content and Links to Other Sites Our sites may contain links to other websites not operated or controlled by us ("Third Party Sites"). The policies and procedures set forth herein do not apply to any Third Party Sites. The owners and operators of all Third Party Sites are responsible for all Personal Data and non-Personal Data provided, collected, maintained, stored or otherwise disclosed on those sites, if any. If there are any links on our sites to any Third Party Sites, such links are provided for convenience only and the presence of the same does not imply that we endorse or have reviewed the Third Party Sites, including their privacy policies, if any. We strongly encourage contacting those sites directly for information on their privacy policies. If you access American Cloud through a link from any of our advertising or marketing partners, the applicable sites may include a frame of the relevant advertising or marketing partner. Nevertheless, the information you provide to us through these framed web pages is collected by us, and our use of such information is governed by this Privacy Policy. If you use a social media platform or your mobile device (or other method of communication) to interact with American Cloud, that platform or application may have a specific privacy statement that governs the use of Personal Data related to it. If you have questions about the security and privacy settings of your mobile device, please refer to instructions from your mobile service provider or the manufacturer of your device to learn how to adjust your settings. We do not control the data collection or privacy practices of any outside platform through which you access the American Cloud or by which you contact us. ## Information Security American Cloud has implemented commercially reasonable information security measures, including administrative, technical and physical controls that are designed to reasonably safeguard Personal Data. Even though we have taken and will continue to implement measures to protect the data which we are entrusted with, you acknowledge that no such measures can fully eliminate all information security risks. Though we take commercially reasonable steps to protect the security and confidentiality of all data and Personal Data provided via the Services from loss, misuse, unauthorized access, inadvertent disclosure, alteration and/or destruction, no online transmission is ever fully secure or error free. Please keep this in mind when disclosing any Personal Data via the Internet or by email. We do not and will not, at any time, ask you to provide your Personal Data or other personal information in a non-secure or unsolicited email or telephone communication. If you receive such an email, please contact us to bring it to our attention. For more information about unsolicited requests for identifying information or other sensitive details, commonly known as "phishing," you can visit the Federal Trade Commission's informational page at www.consumer.ftc.gov/articles/0003-phishing. ## Information From Children American Cloud is directed toward a general audience and is not intended for use by children. We do not knowingly collect or intend to collect Personal Data from anyone who is under the age of 13. We encourage parents and legal guardians to monitor their children's Internet usage and to help enforce our Privacy Policy by instructing their children never to provide Personal Data through the Sites. If you have reason to believe that a child under the age of 13 has provided Personal Data to us, please contact us and we will endeavor to delete that information from our databases. ## Consent to Transfer American Cloud is based in the United States. If you are located outside of the United States, please be aware that any information you provide to us may be transferred to and processed in the United States. By using American Cloud, or providing us with any information, you consent to this transfer, processing and storage of your information in the United States, a jurisdiction in which the privacy laws may be different than those in the country where you reside or are a citizen. ## California Privacy California residents have additional rights regarding the privacy and disclosure of Personal Data, including, but not limited to a right to request that we not sell their Personal Data, as well as a right to be informed about our other uses and disclosures of their Personal Data. American Cloud does not sell your Personal Data, and we use and disclose Personal Data solely in accordance with this Privacy Policy. If you are a California resident and would like additional information about our use of your Personal Data, please contact us as indicated below. ### California Do Not Track Notice California law requires websites to disclose whether they and/or any third party(s) collect Personal Data about their users' online activities over time and across different sites. California law also requires that we disclose how we respond to "do not track" signals and similar mechanisms. We do not currently participate in any "Do Not Track" frameworks that would allow us to respond to signals or other mechanisms from you regarding the collection of your personal or non-personal identifying information. If you would like to learn more about browser tracking signals and "do not track" generally, please visit https://allaboutdnt.org. ## Nevada Privacy If you are a Nevada resident, you may ask us to add you to our opt-out list for possible future sales of certain information that we have collected or will collect about you. To submit such a request, please contact us as indicated below. ## European Union Resident Privacy American Cloud complies with the provisions of the European Union's General Data Protection Regulation ("GDPR") as to any information in its possession regarding EU-based persons ("data subjects"). Accordingly, American Cloud only processes Personal Data on data subjects where it has a lawful basis to do so, which may include the consent of each person (especially in the case of website visitors who provide their information) or compliance with a legal obligation. American Cloud provides notice to all data subjects as required by GDPR Article 13 or 14, as appropriate, and honors the rights of data subjects provided in Articles 12-23, including the right to be forgotten. For more information about American Cloud and the GDPR, please see our GDPR Notice. ## Updates to This Privacy Policy The American Cloud sites and our business may change from time to time. As a result, it may be necessary for us to make changes to this Privacy Policy. We reserve the right to update, change, amend or modify this Privacy Policy at any time and from time to time without prior notice. Please review this policy periodically, and especially before you provide any Personal Data. If we make any material changes to this Privacy Policy, we will post a notice on the American Cloud homepage notifying users of the changes and providing an opportunity for you to take action relative to those changes prior to their implementation. In some cases, we also may send a notice via your American Cloud Account or by email notifying registered users of upcoming changes. Your continued use of the Services after any changes or revisions to this Privacy Policy become effective shall indicate your agreement with the terms of such revised and then-current Privacy Policy. ## Contact Us If you have any questions or concerns about this Privacy Policy, please feel free to contact us at legal@americancloud.io Last updated: Oct 17, 2022. ## GDPR Notice American Cloud complies with the provisions of the European Union's General Data Protection Regulation ("GDPR") as to any information in its possession regarding EU-based persons ("data subjects"). Accordingly, American Cloud only processes Personal Data on data subjects where it has a lawful basis to do so, as set forth more fully in this GDPR Notice. ## American Cloud's Status Under GDPR Under GDPR, American Cloud may be designated as either (i) a "processor" or (ii) a "controller" for certain data sets. ### American Cloud as Processor In most cases, American Cloud will be a "processor." This means that we will store or perform some other set of operations on a data set that contains Personal Data for a customer, at the customer's written direction. If American Cloud is a "processor" under GDPR for a particular data set, we will enter into a processor agreement or data processor addendum. This agreement is required by GDPR and governs the terms of American Cloud's processing of the protected data at issue. ### American Cloud as Controller As set forth in our Privacy Policy, American Cloud also collects and stores certain contract information, payment information, employee records, and other information for the purposes of conducting business, marketing, employment, and more. In these cases, American Cloud is a controller of data. If American Cloud is a "controller" under GDPR, we will comply with applicable GDPR obligations. These include, but are not limited to the following: - Lawfully process data - Enter into processing agreements with any third-party processors prior to sending personal data to such processors - Maintain all required records and provide required modalities for the exercise of rights of the data subject - Retain data only as long as necessary for the purpose for which it was obtained - Provide data subjects with certain required notices - Adopt all required policies and procedures and train employees who handle personal data governed by GDPR - Implement privacy by design and privacy by default with regard to personal data governed by GDPR - Provide required notifications in the event of a data breach ## Transfer Outside of EU/EEA From time to time American Cloud may transfer Personal Data outside of the European Union or European Economic Area. Whenever we do so, appropriate safeguards will be in place, such as the insertion of approved model clauses. American Cloud will only transfer Personal Data to foreign controllers and processors who meet these standards. ## Duration of Storage American Cloud will only store your data as long as required by the basis for processing. For example, we will only store Personal Data that is being processed pursuant to our legitimate interest so long as such interest is present. If we are processing Personal Data based on consent, that consent may be withdrawn by you at any time. Please contact legal@americancloud.io to withdraw such consent. ## Your Rights as a Data Subject American Cloud is committed to fulfilling its obligations concerning the exercise of your rights under GDPR. Please be advised that you have the following rights under GDPR (to the extent GDPR applies to your personal data): - The right to request access to, rectification or erasure (i.e., the right to be forgotten) of personal data or restriction of processing or to object to processing - The right to data portability - The right to lodge a complaint with a supervisory authority - The right to know the source of the data and whether the source was public (in certain circumstances) Should you have any questions regarding the exercise of these rights, please contact us at legal@americancloud.io. We may provide additional information in communications directly with data subjects as necessary. Last updated: Oct 17, 2022. ## DMCA Notice Policy American Cloud respects the intellectual property rights of others and we ask our users to do the same. American Cloud may, in appropriate circumstances and at its discretion, disable and/or terminate the accounts of users of its services who may be repeat infringers. If you believe that your work has been copied in a way that constitutes copyright infringement, please provide American Cloud (in the manner described below) the following information: 1. A physical or electronic signature of a person authorized to act on behalf of the owner of an exclusive right that is allegedly infringed. 2. Identification of the copyrighted work claimed to have been infringed, or, if multiple copyrighted works at a single online site are covered by a single notification, a representative list of such works at that site. 3. Identification of the material that is claimed to be infringing or to be the subject of infringing activity and that is to be removed or access to which is to be disabled, and information reasonably sufficient to permit American Cloud to locate the material. 4. Information reasonably sufficient to permit American Cloud to contact the complaining party, such as an address, telephone number, and, if available, an electronic mail address at which the complaining party may be contacted. 5. A statement that the complaining party has a good faith belief that use of the material in the manner complained of is not authorized by the copyright owner, its agent, or the law. 6. A statement that the information in the notification is accurate, and under penalty of perjury, that the complaining party is authorized to act on behalf of the owner of an exclusive right that is allegedly infringed. American Cloud's agent for notice of claims of copyright infringement can be reached as follows: **BY CERTIFIED MAIL:** Copyright Agent American Cloud LLC 300 Delaware Ave Ste 210 #535 Wilmington, DE 19801 **(312) 909-1879** **legal@americancloud.io** American Cloud can accept submissions via email to legal@americancloud.io, however, due to the nature of email, we cannot guarantee that email will be delivered. Thus, if you submit via email and do not hear back from us confirming receipt within 72 business hours, please submit your notice again via certified mail as noted above. Last updated: Oct 17, 2022. ## Service Level Agreement Subject to the terms and conditions of the American Cloud Services Agreement (the "Agreement") to which this Service Level Agreement ("SLA") is connected, American Cloud will provide Customer with a level of service consistent with the principles expressed below. To the extent that American Cloud does not provide the Services at the levels set forth in this SLA, and Customer is in compliance with all terms and conditions of the Agreement (including the American Cloud Community Policies), American Cloud will credit Customer's account in an amount as provided in this SLA, reflecting percentages of the monthly Fees for the affected Services (each an "SLA Credit"). ## Definitions **"Core Networking Equipment"** means equipment owned or operated by American Cloud, used to provide the Services, including but not limited to servers, switches and routers, as well as any customer equipment that customer has specifically contracted with American Cloud to manage. **"Downtime"** is defined as failure of Core Networking Equipment, and such failure being verifiable by documentation provided by Customer. However, "Downtime" does not include any of the following: - Scheduled Maintenance or Emergency Maintenance (as defined below). - Outages not reported, or falsely reported. - Problems with the Customer's internet connectivity or problems with other internet providers' connectivity outside of American Cloud's control. - Issues with e-mail or webmail connectivity. - Issues with access arising from technologies not under American Cloud control, including FTP, POP, IMAP, or SMTP. - Problems with Customer's or any Third Party's hardware, software, or access to the internet, including, but not limited to, Third Party DNS issues. - Use of the Services by any person: (a) in violation of applicable law, (b) in breach of this Agreement (including the American Cloud Community Policies), (c) in conjunction with custom scripting or coding (e.g., CGI, Perl, HTML, ASP, Ruby, PHP, Python, etc.), or (d) by means of any negligent act or omission. - Unavailability of the Services due to Customer's suspension or termination in accordance with the Agreement. Issues relating to Customer Data. - Any force majeure event under the Agreement. - Problems caused by Customer's use of the Services or any Customer End User's use of the Customer Offering after American Cloud advised Customer or any Customer End User to modify such use, if Customer or any Customer End User did not modify its use as advised. **"Emergency Maintenance"** means those instances in which American Cloud or its Third Party service providers: (a) identify situations which, in American Cloud's reasonable discretion, have threatened or may threaten the integrity of the Services or the systems used to provide the Services, and (b) take reasonably necessary measures designed to prevent the situation from progressing into unavailability of the Services, or to otherwise resolve the situation. **"Outage End Time"** is the time at which American Cloud restores the Services to be back online and accessible. **"Outage Start Time"** is the time at which documentation provided by Customer and confirmed by American Cloud shows the Services are experiencing Downtime. **"Scheduled Maintenance"** is that amount of time in which American Cloud or its Third Party service providers: (a) perform updates and upgrades, enhancements and routine maintenance activities that are announced through American Cloud.com at least 24 hours advance notice, and (b) perform Emergency Maintenance, upon reasonable notice in the circumstances provided through American Cloud.com or via electronic communications directed to Customer. **"Uptime"** refers to all time during the term of the Agreement except Downtime. Uptime will be calculated in reference to the number of minutes in each calendar month, measured by American Cloud's internal monitoring systems. For the purpose of the SLA, outages are measured in full minutes and will be rounded, as appropriate, up or down to the nearest full minute (i.e., for portions of minutes less than or equal to thirty seconds, the minute measurement will be rounded down, and for portions of minutes greater than or equal to thirty one seconds, the minute measurement will be rounded up). ## Service Level Commitment American Cloud seeks to provide 99.9% network Uptime, as measured by American Cloud's internal monitoring systems, for each calendar month during the term of the Agreement. Subject to the terms and conditions of this SLA, American Cloud will provide to Customer an SLA Credit of 5% of the Fees for the affected Service for each entire 30 minutes of Downtime in a calendar month. For the purpose of calculating Downtime, all times will be rounded, as appropriate, up or down to the nearest full minute (i.e., for portions of minutes less than thirty seconds, the minute measurement will be rounded down, and for portions of minutes greater than thirty seconds, the minute measurement will be rounded up). Uptime is calculated by dividing the number of minutes of network and power related Downtime, as calculated above, and dividing into it the total number of minutes in the calendar month and then subtracting the product from 100%. ## General Terms Applicable to This SLA ### Requesting and Receiving SLA Credits American Cloud will have no obligation to issue any SLA Credit unless requested to do so by Customer in accordance with the terms and conditions of this SLA. Customer must submit all requests for SLA Credit by sending an email message to contact@americancloud.com. Each e-mail request must include, as applicable, the service, product and domain affected in the "Subject" line, and the body of the email must contain a written itemized description of the issue, the affected Service(s), and date and time (with time zone) of the incident. This itemization must be in sufficient detail for American Cloud to identify the issue and must be received by American Cloud within twenty-four (24) hours after the incident. Approved SLA Credits will be applied within two billing cycles after American Cloud's receipt of a valid request. ### Limits on SLA Credit The SLA Credits to Customer in a particular month under this SLA will not exceed the total amount of Fees paid by Customer for such month for the affected Services. To be eligible for any SLA Credits, Customer must not be in default of any provision of the Agreement, including but not limited to the payment of Fees. Additionally, in the event that American Cloud recommends to Customer certain hardware, software or other configurations or technologies in order to meet Customer's then-current specifications, and Customer declines to adopt such recommendation, SLA Credits will not be available for any Downtime that would not have occurred had the recommendation been implemented. Credits are available only toward future payment of Fees and will not be applied to past due balances. SLA Credits will not be applied to any applicable taxes charged to Customer or collected by American Cloud and are Customer's sole and exclusive remedy with respect to any failure by American Cloud to provide the Services. SLA Credit will not be applied to any portion of the Fees allocable to the payment of software licensing or other fees payable by American Cloud to any Third Party, such fees being due from Customer notwithstanding any instance that would give rise to SLA Credit under this SLA. ### Affected Services Only SLA Credits are calculated only for the impacted portion of the Services (e.g., the exact server(s), cloud instances or tickets that experienced the issue). SLA Credits will not be calculated against the Fees for an entire account unless all portions of the Services under that account are impacted. ### Additional Documentation and Limitations American Cloud may require, in its sole discretion, and as a condition for the issuance of SLA Credits, that Customer provide documentation that reasonably supports and demonstrates all actual losses sustained by Customer due to a violation by American Cloud of this SLA. Customer agrees that in the event its actual direct losses do not exceed the value of SLA Credits to which Customer may be entitled under this Agreement, American Cloud may, at its option, provide credit to Customer in the amount of Customer's actual direct losses caused by violation of this SLA. ### Eligibility Not Cumulative Customer's eligibility to receive SLA Credits is not cumulative, but is limited to one SLA Credit per incident. By way of example, if there is more than one cause for an incident of Downtime, Customer will be eligible for only one SLA Credit, corresponding to the length of time of the incident (not two SLA Credits). American Cloud will apply SLA Credits based on the predominant issue with the problem, as determined in American Cloud's reasonable discretion, and will issue the larger of two credits should two equally important issues occur in the same incident. ### Minimum Credits Customer must accrue a minimum amount of $5.00 in SLA Credits before American Cloud will apply such credits. All SLA Credits will be tracked with Customer's account, and American Cloud will apply the SLA Credit when the above-stated minimum is met. No SLA Credits will be applied to any terminated Customer account. ### Maximum Credits Customer's maximum combined SLA Credits for any calendar month for any affected Services shall not exceed the total amount that Customer was charged for those affected Services during the applicable calendar month. Last updated: Oct 17, 2022. ## Open Source ## Open Source Software Used - **Cloudstack** — [Link to Project](https://github.com/apache/cloudstack) - **PDNS** — [Link to Project](https://github.com/PowerDNS/pdns) - **KubeBlocks** — [Link to Project](https://github.com/apecloud/kubeblocks) - **Ceph** — [Link to Project](https://github.com/ceph/ceph)