---
title: "Install Nomad, Podman, and Traefik for Home Selfhosting"
description: "Nomad is a _scheduler_ developed by\nHashicorp, which can be used to schedule\n_containers_, _raw execution_, and other applications. This unique feature\nmakes Nomad capable of running various types of ..."
publishedAt: 2025-02-15
locale: en
urlSlug: install-nomad-untuk-selfhosting
isDraft: false
defaultLocale: en
---
[TOC]

## Background

[Nomad](https://www.nomadproject.io/) is a _scheduler_ developed by
[Hashicorp](https://www.hashicorp.com), which can be used to schedule
_containers_, _raw execution_, and other applications. This unique feature
makes Nomad capable of running various types of applications, not just
containers through the [Task Driver](https://developer.hashicorp.com/nomad/docs/drivers)
concept.

## Prerequisites

### Knowledge Requirements

- Basic understanding of containerization (Docker, Podman, etc.)
- Basic knowledge about Load balancer (Traefik)

### Required Environment

What needs to be prepared:
- Host server with Ubuntu 21.04 OS
- [hashi-up](https://github.com/jsiebens/hashi-up) - CLI tool to simplify
the installation process

### Important Notes

- Installation will be done in _single-node_ mode
- The Nomad server will serve dual purposes:
    - As a server
    - As a client to run workloads
- This mode is chosen to reduce resource requirements

## Installation

Make sure the target server can be accessed via SSH key. Then run the following command:

```bash
hashi-up nomad install \
  --ssh-target-addr 192.168.1.10 \
  --ssh-target-user ubuntu \
  --ssh-target-key ~/.ssh/id_ed25519 \
  --server
```

Please make sure to replace the IP, user, and SSH key address according to
your environment.

## Podman Task Driver

Podman is one of the task drivers supported by Nomad. Why choose Podman?
Because recently I've been using Podman as my daily driver. The installation
process can follow the guide from Nomad's official documentation on
[this page](https://developer.hashicorp.com/nomad/plugins/drivers/podman#installation).

Additionally, make sure Podman is already installed.

```bash
sudo apt install podman
```

Next, we need to ensure that Nomad recognizes this plugin.

```bash
sudo vim /etc/nomad.d/nomad.hcl
```

Add the following lines.

```hcl
# generated with hashi-up

datacenter = "dc1"
data_dir   = "/opt/nomad"
plugin_dir = "/opt/nomad/data/plugins" # [!code ++]
server {
  enabled          = true
  bootstrap_expect = 1
}
plugin "nomad-driver-podman" {      # [!code ++]
  enabled = true                    # [!code ++]
}                                   # [!code ++]
```

Restart the Nomad server.

```bash
sudo systemctl restart nomad
```

Make sure the plugin appears in the task driver section.

```bash
nomad node status -self -short | grep Drivers
CSI Drivers     = <none>
Drivers         = exec,podman
```

## Nomad Single Node

To run Nomad as a _single-node_, we need to enable client mode
on this Nomad server. Edit the file `/etc/nomad.d/nomad.hcl` again and add
the following lines:

```hcl
# generated with hashi-up

datacenter = "dc1"
data_dir   = "/opt/nomad"
plugin_dir = "/opt/nomad/data/plugins"
server {
  enabled          = true
  bootstrap_expect = 1
}
client {                            # [!code ++]
    enabled = true                  # [!code ++]
}                                   # [!code ++]
```

Don't forget to restart the nomad service

## Traefik and Nomad service discovery

Open nomad webui through your browser, usually at `http://192.168.1.10:4646/ui`. Then
click the "Run job" button and add the following job specification:

```hcl
job "traefik" {
  datacenters = ["dc1"]
  type        = "service"

  group "traefik" {
    count = 1

    network {
      port "http" {
        static = 8080
      }

      port "admin" {
        static = 8081
      }
    }

    service {
      name     = "traefik-http"
      provider = "nomad"
      port     = "http"
    }

    task "server" {
      driver = "podman"

      config {
        image = "docker.io/traefik:v2.11.20"
        ports = ["admin", "http"]

        args = [
          "--api.dashboard=true",
          "--api.insecure=true", # Traefik will be installed in insecure mode, preferably not exposed to the internet
          "--entrypoints.web.address=:${NOMAD_PORT_http}",
          "--entrypoints.traefik.address=:${NOMAD_PORT_admin}",
          "--providers.nomad=true",
          "--providers.nomad.endpoint.address=http://${NOMAD_IP_http}:4646",
          "--providers.nomad.exposedByDefault=false"
        ]
      }
    }
  }
}
```

## Deploy demo application

Next, we'll deploy an application that demonstrates simple load balancing
through Traefik that is already connected to Nomad service discovery.

```hcl
job "demo-webapp" {
  datacenters = ["dc1"]

  group "demo" {
    count = 3

    network {
      port  "http"{
        to = -1
      }
    }

    service {
      name = "demo-webapp"
      port = "http"
      provider = "nomad"

      tags = [
        "traefik.enable=true",
        "traefik.http.routers.demo-webapp-http.rule=Host(`demo-webapp-192-168-1-10.nip.io`)",
        "traefik.http.routers.demo-webapp-http.tls=false",
      ]

      check {
        type     = "http"
        path     = "/"
        interval = "2s"
        timeout  = "2s"
      }
    }

    task "server" {
      env {
        PORT    = "${NOMAD_PORT_http}"
        NODE_IP = "${NOMAD_IP_http}"
      }

      driver = "podman"

      config {
        image = "docker.io/hashicorp/demo-webapp-lb-guide"
        ports = ["http"]
      }
    }
  }
}
```

After the above job is run, the `demo-webapp` application will go through the
_Load balancing_ process by Traefik first, then be directed to each container.

```bash
ubuntu@nomad01:~$ curl http://demo-webapp-192-168-1-10.nip.io:8080
Welcome! You are on node 192.168.1.10:20190
ubuntu@nomad01:~$ curl http://demo-webapp-192-168-1-10.nip.io:8080
Welcome! You are on node 192.168.1.10:25458
ubuntu@nomad01:~$ curl http://demo-webapp-192-168-1-10.nip.io:8080
Welcome! You are on node 192.168.1.10:25482
ubuntu@nomad01:~$ curl http://demo-webapp-192-168-1-10.nip.io:8080
Welcome! You are on node 192.168.1.10:20190
```

As you can see, responding to our requests are _several containers_
each with _different_ ports, those ports are allocated by Nomad
dynamically.

That's the short tutorial, in the next article I will discuss how to run
_stateful_ applications like _databases_ with _host volumes_ in Nomad.
