Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Argocd Ubuntu
GUIDEInstall Guides

How to Install ArgoCD on Ubuntu 24.04 VPS: GitOps Continuous Delivery for Kubernetes

27 min read

How to Install ArgoCD on Ubuntu 24.04 VPS: GitOps Continuous Delivery for Kubernetes

ArgoCD turns your Git repository into the single source of truth for everything running inside a Kubernetes cluster. You commit a change to a manifest, ArgoCD notices the drift, and it reconciles the cluster back to what your repository says it should be. This guide walks through installing ArgoCD on Ubuntu 24.04 on top of a lightweight K3s cluster, exposing the UI with TLS, connecting private Git repos, wiring up SSO with Dex, and deploying your first application using the App-of-Apps pattern.

Why self-host? Running ArgoCD on your own VPS keeps cluster credentials, SSH deploy keys, and deployment history entirely under your control — no SaaS middleman touches your kubeconfig or your private repos.

Table of Contents

  • What is ArgoCD?
  • Why Self-Host ArgoCD on Your VPS?
  • Prerequisites
  • Step 1: Prepare the Ubuntu 24.04 Host
  • Step 2: Install K3s (Lightweight Kubernetes)
  • Step 3: Install kubectl and Helm
  • Step 4: Install ArgoCD via Helm
  • Step 5: Initial Login and Admin Password
  • Step 6: Install and Log In with the argocd CLI
  • Step 7: Expose ArgoCD with TLS via Ingress
  • Step 8: Connect a Private Git Repository
  • Step 9: Deploy Your First App (App-of-Apps Pattern)
  • Step 10: Configure SSO with Dex and OIDC
  • Step 11: RBAC and Team Permissions
  • Step 12: Automate Image Updates with Argo CD Image Updater
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is ArgoCD?

    ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes. It watches Git repositories containing Kubernetes manifests, Helm charts, Kustomize overlays, or Jsonnet, and continuously reconciles the live cluster state with what the repository declares. If someone manually edits a Deployment in the cluster, ArgoCD detects the drift and (if configured) reverts it. If you merge a commit that bumps an image tag, ArgoCD rolls the change out.

    The core primitive is the Application custom resource — a pointer to a source (Git repo, path, target revision) and a destination (cluster + namespace). ArgoCD's application-controller reconciles each Application on a loop, running a three-way diff between the Git-declared state, the cluster's live state, and the last-known-applied state. Sync strategies range from fully manual (you click "Sync" in the UI) to fully automated with self-heal, automatic pruning of deleted resources, and optional sync hooks for pre-sync migrations or post-sync smoke tests.

    Beyond plain Applications, ArgoCD ships ApplicationSet for fan-out patterns (one template, many generated Applications across clusters or matrix dimensions), AppProject for multi-tenant isolation (restrict which repos, destinations, and resource kinds a team can use), and Rollouts integration for progressive delivery with blue/green and canary strategies. The UI gives you a topology view of every resource an Application owns, real-time sync status, and a one-click diff against Git.

    Typical use cases include managing platform components (ingress controllers, cert-manager, monitoring) across many clusters from a single repo, deploying microservices with per-environment overlays, running preview environments for pull requests via ApplicationSet generators, and enforcing compliance by making Git the only path to production.

    Why Self-Host ArgoCD on Your VPS?

    You can pay for a hosted GitOps platform, but self-hosting ArgoCD on your own VPS offers concrete wins:

    • Cost predictability — A single VPS running K3s + ArgoCD handles dozens of Applications and multiple external clusters for a flat monthly fee. Hosted GitOps tiers often charge per user, per cluster, or per Application.
    • Credentials stay with you — ArgoCD stores kubeconfigs, SSH deploy keys, Helm repo credentials, and SSO client secrets as Kubernetes Secrets inside your cluster. Nothing leaves your VPS.
    • Private network access — Your ArgoCD instance can reach internal Git servers (self-hosted Gitea, GitLab, Forgejo) over a VPN or private network without exposing them publicly.
    • No rate limits — Hosted control planes throttle API calls and sync frequency. On your own hardware, the only limit is the hardware itself.
    • Full extensibility — Install any config management plugin (cmp-server), wire up Argo CD Image Updater, enable ApplicationSets, run Argo Rollouts — all without waiting for a vendor to enable a feature flag.
    • Regulatory and compliance fit — For teams under GDPR, HIPAA, SOC 2, or similar regimes, keeping the CD control plane on infrastructure you control simplifies the data-flow diagram and the auditor conversation.

    Recommended VPS

    For a single-cluster ArgoCD install running K3s + ArgoCD + a handful of managed Applications, we recommend the CloudCore Professional plan:

    • 6 vCPU cores
    • 12 GB RAM
    • 100 GB NVMe SSD
    • Unmetered bandwidth
    That gives you enough headroom for K3s, the ArgoCD components (api-server, repo-server, application-controller, Redis, Dex), and the actual workloads you will manage. If you only want ArgoCD as a control plane and plan to target external clusters, a smaller plan works, but the above is the sweet spot for most teams.

    Browse VPS plans — plans start well below the cost of a single hosted-GitOps user seat.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • At least 4 GB of RAM (8 GB+ recommended for comfortable K3s + ArgoCD operation)
    • At least 20 GB of free disk space
    • A public IP and a domain name (e.g. argocd.example.com) with an A record pointing to the VPS, if you want HTTPS access
    • SSH access to the VPS
    • A Git repository you want ArgoCD to manage (GitHub, GitLab, Gitea, Forgejo — anything that speaks HTTPS or SSH)
    If you have not yet installed Kubernetes, follow How to Install K3s on Ubuntu first. For Docker-based workflows on the same host, see How to Install Docker on Ubuntu. If you prefer terminating TLS on Nginx instead of the K3s-bundled ingress, see How to Install Nginx on Ubuntu.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Prepare the Ubuntu 24.04 Host

    Update system packages and install a couple of small utilities we will need later:

    bash
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl ca-certificates apt-transport-https gnupg git

    Set the hostname (optional but tidy when you have multiple clusters):

    bash
    sudo hostnamectl set-hostname argocd-01

    Open the firewall for the ports K3s and ArgoCD need:

    bash
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw allow 6443/tcp
    sudo ufw --force enable

    Port 6443 is the Kubernetes API. You can restrict it to your office IP in production.

    Step 2: Install K3s (Lightweight Kubernetes)

    K3s is a fully conformant Kubernetes distribution packaged into a single ~60 MB binary. It is ideal for single-node ArgoCD installs because it bundles containerd, a Traefik ingress controller, local-path storage, and a service load balancer (klipper-lb) out of the box.

    Install K3s:

    bash
    curl -sfL https://get.k3s.io | sh -

    Expected output:

    text
    [INFO]  Finding release for channel stable
    [INFO]  Using v1.30.x+k3s1 as release
    [INFO]  Downloading hash ...
    [INFO]  Downloading binary ...
    [INFO]  systemd: Enabling k3s unit
    [INFO]  systemd: Starting k3s

    Verify the cluster is up:

    bash
    sudo k3s kubectl get nodes

    Expected output:

    text
    NAME         STATUS   ROLES                  AGE   VERSION
    argocd-01    Ready    control-plane,master   30s   v1.30.x+k3s1

    K3s writes its kubeconfig to /etc/rancher/k3s/k3s.yaml and restricts it to root. Copy it to your user and adjust permissions so kubectl (installed next) can use it:

    bash
    mkdir -p ~/.kube
    sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
    sudo chown "$(id -u):$(id -g)" ~/.kube/config
    chmod 600 ~/.kube/config

    If you want to access the cluster from your laptop, copy ~/.kube/config to your workstation and replace server: https://127.0.0.1:6443 with server: https://your-server-ip:6443.

    Step 3: Install kubectl and Helm

    K3s ships its own kubectl via k3s kubectl, but installing the upstream binary gives you shell completion and tab-friendly ergonomics.

    Install kubectl:

    bash
    curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
    sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
    kubectl version --client

    Install Helm:

    bash
    curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    helm version

    Expected output:

    text
    version.BuildInfo{Version:"v3.15.x", GitCommit:"...", GoVersion:"go1.22.x"}

    Verify kubectl can reach the cluster:

    bash
    kubectl get nodes -o wide
    kubectl get pods -A

    You should see core K3s pods in kube-system (coredns, traefik, local-path-provisioner, metrics-server) all Running.

    Step 4: Install ArgoCD via Helm

    The official Argo project maintains a Helm chart at argoproj/argo-helm. Add the repo:

    bash
    helm repo add argo https://argoproj.github.io/argo-helm
    helm repo update

    Create a dedicated namespace:

    bash
    kubectl create namespace argocd

    Create a values file tuned for a single-node VPS. This disables the built-in dex-server for now (we will enable SSO later), sets the controller/repo-server to sensible resource requests, and leaves the server running in insecure mode behind the ingress (the ingress terminates TLS):

    bash
    cat > argocd-values.yaml <<'EOF'
    global:
      domain: argocd.example.com

    configs: params: server.insecure: true

    server: extraArgs: - --insecure service: type: ClusterIP resources: requests: cpu: 100m memory: 256Mi

    controller: resources: requests: cpu: 250m memory: 512Mi

    repoServer: resources: requests: cpu: 100m memory: 256Mi

    redis: resources: requests: cpu: 50m memory: 64Mi

    dex: enabled: false

    applicationSet: enabled: true

    notifications: enabled: true EOF

    Replace argocd.example.com with your actual domain.

    Install the chart:

    bash
    helm install argocd argo/argo-cd \
      --namespace argocd \
      --values argocd-values.yaml \
      --version 7.x.x

    Pin the chart version explicitly in production. Check the chart releases for the latest argo-cd-* tag.

    Wait for all pods to become ready:

    bash
    kubectl get pods -n argocd -w

    Expected final state:

    text
    NAME                                                READY   STATUS    RESTARTS   AGE
    argocd-application-controller-0                     1/1     Running   0          2m
    argocd-applicationset-controller-xxxxxxxxxx-xxxxx   1/1     Running   0          2m
    argocd-notifications-controller-xxxxxxxxxx-xxxxx    1/1     Running   0          2m
    argocd-redis-xxxxxxxxxx-xxxxx                       1/1     Running   0          2m
    argocd-repo-server-xxxxxxxxxx-xxxxx                 1/1     Running   0          2m
    argocd-server-xxxxxxxxxx-xxxxx                      1/1     Running   0          2m

    Press Ctrl+C once everything is Running.

    Step 5: Initial Login and Admin Password

    ArgoCD generates a random initial admin password and stores it in a Secret. Retrieve it:

    bash
    kubectl -n argocd get secret argocd-initial-admin-secret \
      -o jsonpath="{.data.password}" | base64 -d; echo

    Expected output:

    text
    Abc123XYZ...randomstring

    Port-forward the server to your laptop (quickest way to test before we set up ingress):

    bash
    kubectl port-forward svc/argocd-server -n argocd 8080:443

    Open https://localhost:8080 in your browser. You will see a self-signed certificate warning — accept it for now. Log in with:

    • Username: admin
    • Password: the value from the command above
    Once logged in, change the admin password immediately. The ArgoCD docs explicitly recommend deleting the initial admin secret after rotating the password:

    bash
    kubectl -n argocd delete secret argocd-initial-admin-secret

    Step 6: Install and Log In with the argocd CLI

    The argocd CLI is how you script everything ArgoCD does. Install the latest release:

    bash
    ARGOCD_VERSION=$(curl -L -s https://raw.githubusercontent.com/argoproj/argo-cd/stable/VERSION)
    curl -sSL -o argocd "https://github.com/argoproj/argo-cd/releases/download/v${ARGOCD_VERSION}/argocd-linux-amd64"
    sudo install -m 555 argocd /usr/local/bin/argocd
    rm argocd
    argocd version --client

    With the port-forward still running in another terminal, log in:

    bash
    argocd login localhost:8080 \
      --username admin \
      --password 'your-new-password' \
      --insecure

    Verify:

    bash
    argocd cluster list
    argocd app list

    The in-cluster Kubernetes target is registered automatically as https://kubernetes.default.svc.

    Change the admin password from the CLI (alternative to the UI):

    bash
    argocd account update-password

    Step 7: Expose ArgoCD with TLS via Ingress

    For production, skip the port-forward and expose ArgoCD via the K3s-bundled Traefik ingress with an automatically issued Let's Encrypt certificate via cert-manager.

    Install cert-manager:

    bash
    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
    kubectl -n cert-manager wait --for=condition=Available deployment --all --timeout=180s

    Create a ClusterIssuer for Let's Encrypt:

    bash
    cat <<'EOF' | kubectl apply -f -
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: [email protected]
        privateKeySecretRef:
          name: letsencrypt-prod
        solvers:
          - http01:
              ingress:
                class: traefik
    EOF

    Create an Ingress for the ArgoCD server:

    bash
    cat <<'EOF' | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: argocd-server
      namespace: argocd
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        traefik.ingress.kubernetes.io/router.entrypoints: websecure
    spec:
      ingressClassName: traefik
      rules:
        - host: argocd.example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: argocd-server
                    port:
                      number: 80
      tls:
        - hosts:
            - argocd.example.com
          secretName: argocd-server-tls
    EOF

    Because we installed ArgoCD with server.insecure: true, the server speaks plain HTTP inside the cluster and Traefik terminates TLS at the edge. That is the officially supported pattern documented in the ArgoCD ingress guide.

    Wait for the certificate:

    bash
    kubectl -n argocd get certificate
    kubectl -n argocd describe certificate argocd-server-tls

    Once READY=True, browse to https://argocd.example.com. Log in with your admin credentials. No more self-signed warnings.

    Re-login the CLI against the public URL:

    bash
    argocd logout localhost:8080
    argocd login argocd.example.com

    Step 8: Connect a Private Git Repository

    ArgoCD pulls manifests from Git. For a public HTTPS repo, no credentials are needed. For a private repo, register credentials using the CLI or a Secret.

    HTTPS with a Personal Access Token

    bash
    argocd repo add https://github.com/your-org/your-infra.git \
      --username git \
      --password "$GITHUB_PAT"

    SSH with a Deploy Key

    Generate a dedicated deploy key:

    bash
    ssh-keygen -t ed25519 -f ~/argocd-deploy-key -N ""

    Add the public key (~/argocd-deploy-key.pub) to your Git host as a read-only deploy key. Then register the private key with ArgoCD:

    bash
    argocd repo add [email protected]:your-org/your-infra.git \
      --ssh-private-key-path ~/argocd-deploy-key

    Verify:

    bash
    argocd repo list

    Expected output:

    text
    TYPE  NAME  REPO                                        INSECURE  OCI    LFS    CREDS  STATUS      MESSAGE
    git         [email protected]:your-org/your-infra.git      false     false  false  true   Successful

    Credentials are persisted as Secrets in the argocd namespace (label argocd.argoproj.io/secret-type: repository). You can also declare them in Git and sync them — the bootstrap pattern we use in the next step.

    Step 9: Deploy Your First App (App-of-Apps Pattern)

    The App-of-Apps pattern is the canonical way to bootstrap a cluster: you create one root Application that points at a directory of other Application manifests, and ArgoCD recursively creates all of them. This turns "everything on the cluster" into a Git-managed, pull-request-reviewed artifact.

    In your Git repo, create this layout:

    text
    your-infra/
    ├── bootstrap/
    │   └── root.yaml
    └── apps/
        ├── nginx.yaml
        └── monitoring.yaml

    bootstrap/root.yaml — the root Application:

    yaml
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: root
      namespace: argocd
      finalizers:
        - resources-finalizer.argocd.argoproj.io
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/your-infra.git
        targetRevision: main
        path: apps
        directory:
          recurse: true
      destination:
        server: https://kubernetes.default.svc
        namespace: argocd
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

    apps/nginx.yaml — a sample child Application deploying the ingress-nginx Helm chart:

    yaml
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: ingress-nginx
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://kubernetes.github.io/ingress-nginx
        chart: ingress-nginx
        targetRevision: 4.11.x
        helm:
          values: |
            controller:
              service:
                type: ClusterIP
      destination:
        server: https://kubernetes.default.svc
        namespace: ingress-nginx
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

    Commit and push. Then, one-time, apply the root Application:

    bash
    kubectl apply -f bootstrap/root.yaml

    ArgoCD picks up the root Application, which in turn creates every Application under apps/. From this point on, adding a new app is just adding a new file under apps/ and merging a PR — no more kubectl apply on your laptop.

    Watch it sync:

    bash
    argocd app list
    argocd app get root
    argocd app sync root

    Expected output:

    text
    NAME           CLUSTER                         NAMESPACE    PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS
    root           https://kubernetes.default.svc  argocd       default  Synced  Healthy  Auto-Prune  <none>
    ingress-nginx  https://kubernetes.default.svc  ingress-nginx default Synced  Healthy  Auto-Prune  <none>

    Open the UI and you will see a topology tree: the root Application on the left, the child Applications in the middle, and every Kubernetes resource (Deployment, Service, ConfigMap, Pod, etc.) on the right.

    Step 10: Configure SSO with Dex and OIDC

    For a team install, local accounts quickly become unmanageable. ArgoCD ships an embedded Dex server that federates to GitHub, GitLab, Google, Okta, Microsoft Entra ID, and any generic OIDC provider.

    First, re-enable Dex. Update your argocd-values.yaml:

    yaml
    dex:
      enabled: true

    configs: cm: url: https://argocd.example.com dex.config: | connectors: - type: github id: github name: GitHub config: clientID: $dex.github.clientID clientSecret: $dex.github.clientSecret orgs: - name: your-github-org

    Create the GitHub OAuth app at https://github.com/organizations/your-github-org/settings/applications:

    • Homepage URL: https://argocd.example.com
    • Authorization callback URL: https://argocd.example.com/api/dex/callback
    Copy the generated Client ID and Client Secret, then stash them in a Secret that Dex reads at startup:

    bash
    kubectl -n argocd create secret generic argocd-secret \
      --from-literal=dex.github.clientID=YOUR_CLIENT_ID \
      --from-literal=dex.github.clientSecret=YOUR_CLIENT_SECRET \
      --dry-run=client -o yaml | kubectl apply -f -

    In practice, manage this Secret with sealed-secrets or external-secrets so it can live in Git safely.

    Upgrade the release:

    bash
    helm upgrade argocd argo/argo-cd \
      --namespace argocd \
      --values argocd-values.yaml

    Restart the affected deployments:

    bash
    kubectl -n argocd rollout restart deployment argocd-server
    kubectl -n argocd rollout restart deployment argocd-dex-server

    Open https://argocd.example.com — you will now see a "LOG IN VIA GITHUB" button. Clicking it redirects to GitHub, authorizes, and drops you back into ArgoCD as an authenticated SSO user.

    For Google Workspace, Okta, or Entra ID, swap the connectors block for the corresponding Dex connector config. The ArgoCD user-management docs list every supported provider.

    Step 11: RBAC and Team Permissions

    Out of the box, any authenticated user has read-only cluster access. To grant granular permissions, edit the RBAC ConfigMap argocd-rbac-cm.

    bash
    cat <<'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: argocd-rbac-cm
      namespace: argocd
    data:
      policy.default: role:readonly
      scopes: "[groups, email]"
      policy.csv: |
        # Built-in admin role
        g, your-github-org:platform-admins, role:admin

    # App developers: sync their own project only p, role:dev, applications, get, dev/*, allow p, role:dev, applications, sync, dev/*, allow p, role:dev, applications, action/, dev/, allow p, role:dev, logs, get, dev/*, allow g, your-github-org:developers, role:dev EOF

    Key points:

    • The first column of policy.csv is p (policy) or g (group-to-role binding).
    • Policies take the form p, <subject>, <resource>, <action>, <object>, <effect>.
    • The <object> for applications is <project>/<app>, so dev/* restricts the developer role to the dev AppProject.
    • policy.default: role:readonly is the fallback for any authenticated user without an explicit binding.
    Create the dev AppProject so the developer role has something to sync:

    yaml
    apiVersion: argoproj.io/v1alpha1
    kind: AppProject
    metadata:
      name: dev
      namespace: argocd
    spec:
      description: Developer-managed applications
      sourceRepos:
        - https://github.com/your-org/dev-apps.git
      destinations:
        - namespace: dev-*
          server: https://kubernetes.default.svc
      clusterResourceWhitelist: []
      namespaceResourceWhitelist:
        - group: "*"
          kind: "*"

    Commit this manifest to your infra repo and let the App-of-Apps pattern apply it. Now developers in the developers GitHub team can sync any Application under project: dev into any dev-* namespace, but cannot touch platform Applications.

    Full syntax is documented at argo-cd.readthedocs.io/en/stable/operator-manual/rbac/.

    Step 12: Automate Image Updates with Argo CD Image Updater

    ArgoCD reconciles Git → cluster. It does not, by itself, bump image tags when you push a new container build. Argo CD Image Updater closes that loop: it polls your container registry for new tags and either writes them back to Git (best practice) or patches the Application directly.

    Install the Helm chart:

    bash
    helm repo add argo https://argoproj.github.io/argo-helm
    helm install argocd-image-updater argo/argocd-image-updater \
      --namespace argocd \
      --set config.argocd.serverAddress=argocd-server.argocd.svc.cluster.local \
      --set config.argocd.plaintext=true

    Annotate an Application to opt it in to image updates (write-back to Git):

    yaml
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: my-api
      namespace: argocd
      annotations:
        argocd-image-updater.argoproj.io/image-list: api=ghcr.io/your-org/my-api
        argocd-image-updater.argoproj.io/api.update-strategy: semver
        argocd-image-updater.argoproj.io/api.allow-tags: regexp:^v[0-9]+\.[0-9]+\.[0-9]+$
        argocd-image-updater.argoproj.io/write-back-method: git
        argocd-image-updater.argoproj.io/git-branch: main
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/your-infra.git
        targetRevision: main
        path: apps/my-api
      destination:
        server: https://kubernetes.default.svc
        namespace: prod

    Now when you push ghcr.io/your-org/my-api:v1.4.2, the image updater:

  • Notices the tag via a registry poll.
  • Writes image: ghcr.io/your-org/my-api:v1.4.2 into a .argocd-source-my-api.yaml override file in your repo.
  • Commits and pushes using the Git credentials you registered in Step 8.
  • ArgoCD sees the commit and syncs the Deployment.
  • You still get the Git audit trail (every image bump is a commit), but you no longer need a CI job to bump tags. The full annotation reference is in the Argo CD Image Updater documentation.

    Troubleshooting

    ProblemCauseSolution
    argocd-server pod CrashLoopBackOffTLS config mismatch when running behind an ingress that also terminates TLSEnsure server.insecure: true in values AND --insecure in server.extraArgs; restart: kubectl -n argocd rollout restart deploy argocd-server
    Unable to load data: connection refused in UIargocd-repo-server not reachableCheck pod: kubectl -n argocd get pod -l app.kubernetes.io/name=argocd-repo-server; check logs for credentials errors
    Ingress returns 404 page not foundWrong ingressClassName or ArgoCD Service in a different namespaceVerify kubectl get ingressclass matches the one in your Ingress; ensure backend service is argocd-server in namespace argocd
    repository not accessible on repo addWrong credentials or private repo without credsRe-run argocd repo add with --username/--password or --ssh-private-key-path; for self-signed Git hosts add --insecure-skip-server-verification
    ComparisonError: repository not foundTypo in repoURL or repo not yet connectedList with argocd repo list; ensure repoURL in Application matches exactly (trailing .git, case)
    App stuck in OutOfSync despite auto-syncSync policy not set or a resource is ignoredCheck spec.syncPolicy.automated; inspect argocd app diff <app> for what differs
    certificate is not yet ready on ingresscert-manager HTTP-01 challenge failingVerify DNS A record resolves to the VPS; check kubectl describe challenge -A; ensure port 80 is open
    SSO login loops back to ArgoCDDex url or callback URL mismatchEnsure configs.cm.url matches the public URL AND the OAuth app callback is <url>/api/dex/callback
    image updater not bumping tagsMissing Git write-back credentialsRegister a Secret with git credentials and reference it via argocd-image-updater.argoproj.io/write-back-target: helmvalues annotations; see Image Updater docs
    application controller high memoryToo many Applications on a small VPSBump controller.resources.requests.memory and upgrade VPS; consider sharding with ARGOCD_CONTROLLER_REPLICAS

    Reading the logs

    The three most useful log streams:

    bash
    kubectl -n argocd logs -f deploy/argocd-server
    kubectl -n argocd logs -f deploy/argocd-repo-server
    kubectl -n argocd logs -f statefulset/argocd-application-controller

    For sync-specific debugging:

    bash
    argocd app get <app-name> --show-operation
    argocd app history <app-name>
    argocd app manifests <app-name>

    FAQ

    Do I need a Kubernetes cluster to run ArgoCD?

    Yes — ArgoCD itself runs as a set of Kubernetes controllers. It is not a standalone binary. For a single-VPS setup, K3s is the lightest path (installs in 30 seconds, uses ~500 MB RAM at idle). If you already run Docker, you can also use k3d or kind, but for a production VPS, native K3s is preferable because it survives reboots and integrates with systemd. See our K3s install guide for a full walkthrough.

    Can ArgoCD manage clusters other than the one it runs on?

    Yes — this is one of its killer features. You register an external cluster once with argocd cluster add <context-name>, which creates a Secret containing the kubeconfig. From then on, any Application can target that cluster via spec.destination.server: https://api.external-cluster.example.com. A single ArgoCD control plane on a small VPS can manage dozens of downstream production clusters. Make sure the control plane VPS can reach each cluster's API server (via public IP, VPN, or a tunnel).

    How is ArgoCD different from Flux?

    Both are CNCF graduated GitOps projects and both pull from Git. The main practical differences: ArgoCD has a polished web UI and is application-centric (the Application CRD is the unit of deployment); Flux is GitOps-source-centric (you declare GitRepository and Kustomization resources with no built-in UI, though Weave GitOps provides one). ArgoCD's ApplicationSet is more flexible for multi-cluster fan-out; Flux's Kustomize controller handles Kustomize natively without needing a plugin. Teams that want a UI-driven, application-first experience tend to pick ArgoCD. Teams doing heavy Kustomize multi-tenancy with minimal UI tend to pick Flux. Both are production-grade.

    How do I back up ArgoCD state?

    ArgoCD is largely stateless — its desired state lives in Git. The things you should back up are the argocd namespace Secrets (repository credentials, cluster credentials, SSH keys, OIDC client secrets) and any ConfigMaps you have customized (argocd-cm, argocd-rbac-cm, argocd-notifications-cm). Export them with kubectl -n argocd get secret,configmap -o yaml > argocd-backup.yaml. Better: manage them as sealed-secrets or external-secrets in Git so recovery is just re-applying the bootstrap. For disaster recovery at the cluster level, take a snapshot of the VPS volume or use K3s etcd snapshots (k3s etcd-snapshot save).

    Is it safe to expose ArgoCD to the public internet?

    With HTTPS (via cert-manager), SSO enabled (Dex or OIDC), the initial admin account disabled, and proper RBAC, yes — it is a reasonable production posture and is what most teams do. Additional hardening: put ArgoCD behind a WAF or Cloudflare, disable the local admin account entirely (accounts.admin.enabled: false), enforce MFA at the IdP level, and restrict source IPs on the Ingress for the /api path. For extra paranoia, keep ArgoCD on a private VPN and expose only through Tailscale or a Cloudflare Tunnel. See How to Install Nginx on Ubuntu if you prefer terminating TLS in front of K3s instead of at the Traefik ingress.

    What resources does a small ArgoCD install actually use?

    On an idle single-node cluster managing ~10 Applications: roughly 1.5 GB RAM and 0.3 CPU cores total across all ArgoCD components. The application-controller is the heaviest — it holds the reconciliation cache in memory and scales with the number of managed resources. Expect +100-200 MB per 100 additional Applications. The 6 vCPU / 12 GB CloudCore Professional plan handles a few hundred Applications comfortably.

    Can I run ArgoCD with Docker Compose instead of Kubernetes?

    No supported path. ArgoCD is fundamentally a Kubernetes controller — the entire reconciliation model assumes a Kubernetes API to watch and patch. If you want GitOps-style delivery for pure Docker workloads, look at Portainer's Git integration, Komodo, or Coolify. If you already use Docker for other things, installing K3s alongside it is straightforward — see How to Install Docker on Ubuntu.

    How do I upgrade ArgoCD?

    Because you installed via Helm, upgrades are a single command:

    bash
    helm repo update
    helm upgrade argocd argo/argo-cd \
      --namespace argocd \
      --values argocd-values.yaml \
      --version <new-chart-version>

    Always read the release notes between your current version and the target — ArgoCD occasionally changes CRDs across minor versions, which require a one-time kubectl apply -f of the updated CRD manifests before the Helm upgrade. Test in a staging cluster first.

    Next Steps

    • Deploy Argo Rollouts for progressive delivery — Layer Argo Rollouts on top of ArgoCD to run blue/green and canary deployments driven by Prometheus metrics.
    • Add notifications — Wire up the bundled argocd-notifications controller to send Slack, Telegram, or email alerts on sync failures, health degradations, and new deployments.
    • Move to ApplicationSet for multi-env fan-out — Replace manual per-environment Application manifests with an ApplicationSet that generates one Application per directory, per Git branch, or per cluster.
    • Integrate secret management — Install External Secrets Operator or sealed-secrets so every Secret in your infra repo is safely versioned in Git.
    • Harden the cluster — Enable network policies, pod security admission, and audit logging on K3s. See our K3s install guide for the production checklist.

    Need more horsepower? The CloudCore Professional plan gives you 6 vCPU, 12 GB RAM, and 100 GB NVMe — enough to run K3s, ArgoCD, and a realistic fleet of managed Applications on a single VPS. Browse plans.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket