---
# System prepended metadata

title: Airgapped RKE2 with Hauler on RHEL9

---

:::info
:bulb:This is an example of installing RKE2 in an airgap with the use of Hauler
:::

## :question:Purpose
:::success
Installing RKE2 in an airgapped environment
:::

## :feet:Pre-Req steps
:::success
Pre-reqs make sure you have the tools and configurations to successfully complete all the main steps.
:::
1. Install Hauler (https://github.com/hauler-dev/hauler)

Linux/Darwin 
```
# installs latest release
curl -sfL https://get.hauler.dev | bash
```
Homebrew
```
# installs latest release
brew tap hauler-dev/homebrew-tap
brew install hauler
```
2. Hauler login
```
hauler login -u <redacted> -p <redacted> rgcrprod.azurecr.us
```
3. Carbide Public Key
```
curl -sfOL https://raw.githubusercontent.com/rancherfederal/carbide-releases/main/carbide-key.pub
```
4. Install kubectl
```
# Download the latest stable release for your architecture (e.g., AMD64)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

# Make the binary executable
chmod +x ./kubectl

# Move the executable to a directory in your PATH (e.g., /usr/local/bin)
sudo mv ./kubectl /usr/local/bin/kubectl

# Verify the installation
kubectl version --client
```
5. Install helm
```
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4
chmod 700 get_helm.sh
./get_helm.sh
#verify 
helm version
```
6. Disable Firewalld
```
systemctl stop firewalld
systemctl disable firewalld
```


## :feet:Main Steps
:::success
Start
:::

1. Pull down rke2 with hauler
```
hauler store sync --products rke2=v1.35.2+rke2r1 --platform linux/amd64
```
2. Copy files to the airgap
3. Create the config.yaml and registries.yaml files
:::info
token = a joining password so additional nodes server/agent can join the cluster. Only used for initial join
:::
```
mkdir -p /etc/rancher/rke2
cat <<EOF > /etc/rancher/rke2/config.yaml
system-default-registry: rgcprod.azurecr.us
token: somedumbtoken
tls-san:
  - "<your loadbalancer/vip>"
EOF

cat <<EOF > /etc/rancher/rke2/registries.yaml
mirrors:
  "*":
    endpoint:
      - http://localhost:5000
configs:
  "localhost:5000":
    tls:
      insecure_skip_verify: true
EOF
```
:::info
For nodes 2/3/etc you will need a server line in the config file
:::
```
mkdir -p /etc/rancher/rke2
cat <<EOF > /etc/rancher/rke2/config.yaml
system-default-registry: rgcprod.azurecr.us
token: somedumbtoken
server: "https://<your ip>:9345"
tls-san:
  - "<your loadbalancer/vip>"
EOF

cat <<EOF > /etc/rancher/rke2/registries.yaml
mirrors:
  "*":
    endpoint:
      - http://localhost:5000
configs:
  "localhost:5000":
    tls:
      insecure_skip_verify: true
EOF
```
4. Start the registry
```
nohup hauler store serve registry --port 5000
```
5. Pull down the RPMS 
```
curl -sfOL https://github.com/rancher/rke2-selinux/releases/download/v0.21.stable.1/rke2-selinux-0.21-1.el9.noarch.rpm
curl -sfOL https://github.com/rancher/rke2-packaging/releases/download/v1.34.5%2Brke2r1.stable.0/rke2-common-1.34.5.rke2r1-0.el9.x86_64.rpm
curl -sfOL https://github.com/rancher/rke2-packaging/releases/download/v1.34.5%2Brke2r1.stable.0/rke2-server-1.34.5.rke2r1-0.el9.x86_64.rpm
curl -sfOL https://github.com/rancher/rke2-packaging/releases/download/v1.34.5%2Brke2r1.stable.0/rke2-agent-1.34.5.rke2r1-0.el8.x86_64.rpm
```
5. install RKE2
:::info 
make sure you have your registry running if its not on the localhost replace 127.0.0.1 with the appropriate ip or fqdn
:::
```
yum install --disablerepo=* -y rke2-selinux-0.21-1.el9.noarch.rpm rke2-common-1.34.5.rke2r1-0.el9.x86_64.rpm rke2-server-1.34.5.rke2r1-0.el9.x86_64.rpm
```
6. enable the services
```
systemctl enable rke2-server.service
```
7. start the services
```
systemctl start rke2-server.service
```
8. follow the logs
```
journalctl -u rke2-server -f
```
9. inspect the logs
```
journalctl -t rke2
```
:::warning
You will need to wait a minute for everything to successfully start the first time.
:::
10. Validate your install
```
export KUBECONFIG=/etc/rancher/rke2/rke2.yaml
kubectl get pods --all-namespaces
helm ls --all-namespaces
```
example output
kubectl get pods --all-namespaces
```
NAMESPACE     NAME                                                    READY   STATUS      RESTARTS   AGE
kube-system   cloud-controller-manager-linux.local                    1/1     Running     0          69s
kube-system   etcd-linux.local                                        1/1     Running     0          79s
kube-system   helm-install-rke2-canal-6v48b                           0/1     Completed   0          65s
kube-system   helm-install-rke2-coredns-xkwcb                         0/1     Completed   0          65s
kube-system   helm-install-rke2-ingress-nginx-m5bz2                   0/1     Completed   0          65s
kube-system   helm-install-rke2-metrics-server-qmfw5                  0/1     Completed   0          65s
kube-system   helm-install-rke2-runtimeclasses-gftjx                  0/1     Completed   0          65s
kube-system   helm-install-rke2-snapshot-controller-crd-xxtbx         0/1     Completed   0          65s
kube-system   helm-install-rke2-snapshot-controller-flz9l             0/1     Completed   0          65s
kube-system   kube-apiserver-linux.local                              1/1     Running     0          79s
kube-system   kube-controller-manager-linux.local                     1/1     Running     0          71s
kube-system   kube-proxy-linux.local                                  1/1     Running     0          79s
kube-system   kube-scheduler-linux.local                              1/1     Running     0          71s
kube-system   rke2-canal-vwdls                                        2/2     Running     0          60s
kube-system   rke2-coredns-rke2-coredns-5d4dd4bdd9-9zvx5              1/1     Running     0          61s
kube-system   rke2-coredns-rke2-coredns-autoscaler-67b9856946-5r9ql   1/1     Running     0          61s
kube-system   rke2-ingress-nginx-controller-xx4kw                     1/1     Running     0          29s
kube-system   rke2-metrics-server-769f546ff8-v8wh6                    1/1     Running     0          35s
kube-system   rke2-snapshot-controller-858d65d54-8zq2v                1/1     Running     0          37s
```
helm ls --all-namespaces
```
NAME                            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                                   APP VERSION
rke2-canal                      kube-system     1               2026-04-01 04:20:05.555285999 +0000 UTC deployed        rke2-canal-v3.31.3-build2026020600      v3.31.3
rke2-coredns                    kube-system     1               2026-04-01 04:20:05.586015442 +0000 UTC deployed        rke2-coredns-1.45.201                   1.13.1
rke2-ingress-nginx              kube-system     1               2026-04-01 04:20:29.86458405 +0000 UTC  deployed        rke2-ingress-nginx-4.14.303             1.14.3
rke2-metrics-server             kube-system     1               2026-04-01 04:20:30.996555797 +0000 UTC deployed        rke2-metrics-server-3.13.007            0.8.0
rke2-runtimeclasses             kube-system     1               2026-04-01 04:20:28.869351079 +0000 UTC deployed        rke2-runtimeclasses-0.1.000             0.1.0
rke2-snapshot-controller        kube-system     1               2026-04-01 04:20:28.926344308 +0000 UTC deployed        rke2-snapshot-controller-4.2.001        v8.4.0
rke2-snapshot-controller-crd    kube-system     1               2026-04-01 04:20:27.776112101 +0000 UTC deployed        rke2-snapshot-controller-crd-4.2.001    v8.4.0
```


## Completion
:::success
Congratulations you have successfully installed an RKE2 cluster in an airgapped enviornment with hauler!!
:::
If everything was done correctly you should have the first node in your kubernetes cluster up
![screenshot.98](https://hackmd.io/_uploads/HJWSdrss-g.jpg)

:::danger
If you are stuck and need to start over, no worries just uninstall, cleanup, and start over
:::
If you need to restart don't worry
```
/usr/bin/rke2-uninstall.sh
```


Install rancher

ui-plugin.yaml
```
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ui-plugin-catalog
  namespace: cattle-ui-plugin-system
  labels:
    catalog.cattle.io/ui-extensions-catalog-image: ui-plugin-catalog
spec:
  replicas: 1
  selector:
    matchLabels:
      catalog.cattle.io/ui-extensions-catalog-image: ui-plugin-catalog
  template:
    metadata:
      namespace: cattle-ui-plugin-system
      labels:
        catalog.cattle.io/ui-extensions-catalog-image: ui-plugin-catalog
    spec:
      containers:
      - name: server
        image: harbor.linuxlabs.local/rancher/ui-plugin-catalog:4.9.0
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  name: ui-plugin-catalog-svc
  namespace: cattle-ui-plugin-system
spec:
  ports:
    - name: catalog-svc-port
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    catalog.cattle.io/ui-extensions-catalog-image: ui-plugin-catalog
  type: ClusterIP
---
apiVersion: catalog.cattle.io/v1
kind: ClusterRepo
metadata:
  name: ui-plugin-catalog-repo
spec:
  url: http://ui-plugin-catalog-svc.cattle-ui-plugin-system:8080
```