Homelab 1: Cloudflare Tunnel

About project

I have been contemplating the idea of setting up a homelab for quite some time now. As my current VPS subscription is about to expire, I am in need of a dedicated space where I can freely experiment, explore different technologies, and host small projects. Coincidentally, I recently came across Cloudflare Tunnel technology, which allows me to establish a home server even with a dynamic IP provided by my ISP.

Hardware

/posts/vps/homelab_1_cloudflare_tunnel/Hp_EliteDesk_800_G2_Desktop_Mini.jpg

For my hardware selection, I have decided on the HP EliteDesk 800 G2 Mini Desktop. With an Intel Core i5-6500T running at 3.2 GHz, 16GB of RAM, and a 256GB SSD, I believe this setup will adequately meet my exploratory requirements.

OS

After successfully installing Ubuntu Server 22.04 LTS, I found that most of the installation process was straightforward, requiring only a few clicks of the “Next” button. However, there is one crucial step that requires attention. By default, Ubuntu allocates only half of the available storage space, so it is necessary to adjust the “Storage configuration” in order to utilize the entire disk capacity. Here is a quick explanation how to configure

ssh

First I installed ssh server.

sudo apt update
sudo apt install openssh-server
sudo apt install openssh-client

I can check ssh status.

sudo systemctl status ssh

# ● ssh.service - OpenBSD Secure Shell server
#      Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
#      Active: active (running) since Tue 2023-05-23 09:25:17 UTC; 1 day 3h ago
#        Docs: man:sshd(8)
#              man:sshd_config(5)
#     Process: 737 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
#    Main PID: 780 (sshd)
#       Tasks: 1 (limit: 18921)
#      Memory: 7.5M
#         CPU: 365ms
#      CGroup: /system.slice/ssh.service
#              └─780 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

Configuring Uncomplicated FireWall (ufw)

sudo ufw allow ssh
sudo ufw enable
sudo ufw status

# Status: active

# To                         Action      From
# --                         ------      ----
# 22/tcp                     ALLOW       Anywhere
# 22/tcp (v6)                ALLOW       Anywhere (v6)

Connect to the server via ssh. First time I will connect from local network.

# ssh [server-username] [ip-address or domain]
ssh [email protected]

Default configuration using username/password. I will use the user public key instead of the username and password. To do so first I will generate ssh key on the remote machine.

ssh-keygen -t ed25519 -C "<comment>"

Do not enter passphrase when prompted. The private and public keys (id_ed25519 and id_ed25519.pub) will be generated in ~/.ssh/ folder. Next, I will copy the remote machine public key id_ed25519.publine to server ~/.ssh/authorized_keys file.

Test login

# ssh [server-username] [ip-address or domain]
ssh  -o PreferredAuthentications=publickey [email protected]

If all ok disabled password authentification. Create configuration file

cd /etc/ssh/sshd_config.d/
sudo touch disable_root_login.conf
sudo nano disable_root_login.conf

Enter and save

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM yes
PermitRootLogin no

Reload configuration

sudo systemctl reload ssh
sudo systemctl reload sshd

Verify login. This time you should not receive a password prompt.

# ssh [server-username] [ip-address or domain]
ssh [email protected]

Test if you can ssh to localhost. If you receive an error then on the server you have to generate ssh key and add to the servers ~/.ssh/authorized_keys

ssh localhost

Docker

Install docker as per documentation and Doing Linux post-install steps for Docker Engine

To enable docker swarm run the following command.

 docker swarm init

Now we ready to proceed with Cloudflare

Cloudflare Tunel

You will need domain name pointed to Cloudflare name servers. Assuming successfully added domain to Cloudflare.

Launch Zero trust dashbard.

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_001.png

Give tunel name

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_003.png

I will use docker Cloudflate Connector

Cloudflate Connector

Create new docker overlay network

docker network create --driver overlay --attachable project

Create docker-compose.tunnel.yml file with content

version: "3.9"
services:
  tunnel:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    env_file: tunnel.env
    extra_hosts:
      - "host.docker.internal:host-gateway"
    networks:
      - project
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: any
networks:
  project:
    external: true

and tunnel.env

TUNNEL_TOKEN=<PASTE_TOKEN_HERE>

Replace token value with token value from Cloudflare page bellow.

Deploy tunnel If the installation is successful you should see the new connector under the connectors list.

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_004.png

Swarmpit

Install first application. In my case tool for basic docker swarm monitoring.

Create docker-compose.swarmpit.yml file with content

version: "3.3"

services:
  app:
    image: swarmpit/swarmpit:latest
    environment:
      - SWARMPIT_DB=http://db:5984
      - SWARMPIT_INFLUXDB=http://influxdb:8086
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080"]
      interval: 60s
      timeout: 10s
      retries: 3
    networks:
      - net
      - project
    deploy:
      resources:
        limits:
          cpus: "0.50"
          memory: 1024M
        reservations:
          cpus: "0.25"
          memory: 512M
      placement:
        constraints:
          - node.role == manager

  db:
    image: couchdb:2.3.0
    volumes:
      - db-data:/opt/couchdb/data
    networks:
      - net
    deploy:
      resources:
        limits:
          cpus: "0.30"
          memory: 256M
        reservations:
          cpus: "0.15"
          memory: 128M

  influxdb:
    image: influxdb:1.8
    volumes:
      - influx-data:/var/lib/influxdb
    networks:
      - net
    deploy:
      resources:
        limits:
          cpus: "0.60"
          memory: 512M
        reservations:
          cpus: "0.30"
          memory: 128M

  agent:
    image: swarmpit/agent:latest
    environment:
      - DOCKER_API_VERSION=1.35
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - net
    deploy:
      mode: global
      labels:
        swarmpit.agent: "true"
      resources:
        limits:
          cpus: "0.10"
          memory: 64M
        reservations:
          cpus: "0.05"
          memory: 32M

networks:
  net:
    driver: overlay
  project:
    external:
      name: project
volumes:
  db-data:
    driver: local
  influx-data:
    driver: local

Rout your subdomain to docker swarm service http://swarmpit_app.8080

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_005.png

Check if now you can access swarm pit from https://swarmpit.<your_domain>. Most likely you want secure access to this service therefore do following steps

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_006.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_007.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_008.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_009.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_010.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_011.png

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_012.png

ssh access from the internet

Rout your https://ssh.<your_domain> subdomain to ssh server

/posts/vps/homelab_1_cloudflare_tunnel/Zero_Trust_013.png

Install Cloudflared on remote machine. In my case section Ubuntu 22.04 LTS (Jammy Jellyfish)

Cloudflared linux instalation

Other OS installation

Update remote mashine ssh configuration file under ~/.ssh/config.

Add following values

Host ssh.<your_domain>
ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h

You can now test the connection by running a command to reach the service.

ssh <username>@ssh.<your_domain>

Now you have the first running service on home server and can access it remotely.