A headless OMV 7 install running a dockerized GitLab instance.
Written for Linux beginners by a Linux beginner.
Table of Contents
The FriendlyElec CM3588 is a high performance computing module featuring the RK3588 ARM based chip. All of the interesting specs are listed on the main site, a brief datasheet for the Rockchip RK3588 can also be found listing all capabilities of the chip.
The RK3588 is a powerful and efficient 8-core ARM processor. The carrier board sold with the CM3588 features a good selection of connectivity and 4 M.2 drive slots, making it very attractive for a NAS build.
Typical power consumption seems to be in the range of 7-15W depending on load. The CPU usually sits at 55-60C in a closed box with no active ventilation.
I used this very nice case by Fuzzler.
I bought the CM3588 with a very specific purpose in mind. I needed a NAS for having a shared folder in windows that i could access from all of my machines (and from anywhere).
I was also interested in hosting my own GitLab instance, for storing and managing projects. To accomplish this i will be using:
- OpenMediaVault
- Tailscale
- Docker
- GitLab CE
The FriendlyElec Wiki is really good and great source of information, but it can, however, be a bit overwhelming.
The omv-extras Wiki also offers good instructions for setting up Docker in OMV.
This guide by DukeChocula is also quite nice and even details installation of ZFS if that is relevant for you. A lot of the initial OS install of this guide is based on the one by DukeChocula.
I bought the 8GB RAM/64GB eMMc model and will flash the OS to the eMMC over USB. The only requirement is a USB-C cable. The install is headless, meaning that we won't connect a monitor or any peripherals to the CM3588.
- Download
DriverAssitant_v5.12.zip
under tools in the official FriendlyElec Drive. Unzip and install the drivers on the machine flashing the CM3588. - Download
rk3588-usb-debian-bookworm-core-6.1-arm64
under tools > 03_USB upgrade images. - Unzip files in a known location.
- Press and hold the "Mask" key, power on the CM3588. After the status LED has been on for at least 3 seconds, release the "Mask" key and connect a USB cable from the CM3588 to your computer (use the USB-C port on the CM3588).
- Go the the directory where you extracted
rk3588-usb-debian-bookworm-core-6.1-arm64
and startRKDevTool.exe
. You should see "Found a new Maskrom device" message. Click "run". The tool should now install the OS to the CM3588's eMMC. - After a successful install the CM3588 should automatically reboot.
The OS we just installed is Debian 12, also known as Bookworm. Since we are doing a headless install we will login to the CM3588 over the local network using SSH.
- Connect the CM3588 to the local network using a Ethernet cable.
- Login to your router (typically an address like 192.168.1.1).
- Set a static IP for the CM3588 so it won't get reconfigured randomly by DHCP.
- Install PuTTy and SSH into the CM3588 using the new static IP for the CM3588.
- If everything is working you should be prompted to login.
By default there are 2 accounts.
Username: root
Password: fa
Username: pi
Password: pi
The first and most important thing we will do is change the root password. This is really important as the root user has complete system access. Later we will even make it impossible to login to the root user over SSH. This is another important security step as the root user always has username root.
Login to root using the default password fa
. Change password using
passwd
While logged in as root we will delete the default user.
deluser pi
We will now create our own user. You are free to choose a fun name, but i felt particularly inspirationless that day and choose the username nas
.
useradd nas
The newly added user is going to be the primary user we will use when logging in to the CM3588. Set a password and add it to the sudoers group.
passwd nas
usermod -aG sudo nas
From now on we will use the nas user instead of root.
We now have a squeaky clean and fresh Debian install and are ready to install OMV. We will use the official install script (see more here).
sudo wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash
This automatically installs OMV.
It will take some time. When it is done the SSH session will be disconnected.
You should be able to access OMV using the local IP address for the CM3588. Login using the default admin user.
Username: admin
Password: openmediavault
Make sure to change the admin password. You should see the beautiful (but probably empty) OMV dashboard.
We will now disable root login via SSH. We do this step now since OMV would otherwise overwrite this change after install. SSH back into the system.
vim /etc/ssh/sshd_config
Search for PermitRootLogin yes
and change it to PermitRootLogin no
.
systemctl restart ssh
The FriendlyElec Wiki is absolutely excellent for describing the OMV setup process. It fully details drive and user setup as well as setting up a SMB share.
Tailscale can be installed at the system level very easily by
curl -fsSL https://tailscale.com/install.sh | sh
Follow the install script to finalize setup.
The CM3588 should now be added to your Tailnet, allowing access to it and the network share from all Tailscale devices (and with a secure connection).
Login to Tailscale and go to Admin Console > DNS.
Rename your Tailnet or just use the default if you want. In either case note it down. Using Tailscale we can access the CM3588 by typing the tailscale device name (i simply named mine cm3588) followed by the Tailnet address i.e. cm3588.your-tailnet.ts.net.
Make sure MagicDNS is enabled. Also enable HTTPS certificates. A Tailscale connection should always be secure, but we must enable HTTPS for GitLab since many tools will otherwise refuse to work with it (believing it is nonsecure).
- Under System > omv-extras enable "Docker repo" and save.
- Under System > Plugins find a highlight
openmediavault-compose
and click install.
We need to specify some folders where docker related data is stored. The omv-extras Wiki (2. Plugin Settings) details this excellently.
Most importantly is the appdata
folder, as this is where persistent data is stored.
We can create a global environment variable for the appdata folder path. Go to Services > Compose > Files and click on "Edit global environment file". Add the following line
PATH_TO_APPDATA=<path-to-your-appdata>
Docker is now ready.
We will be using GitLab CE. At the moment there is no official support for running GitLab in Docker for ARM64. There is however a unofficial docker image that works well.
Getting GitLab working is easy enough using Docker compose. There is, however, a little challenge in getting it to work nicely with Tailscale and glab (GitLab CLI).
Under Services > Compose > Files create a new file. I used the following docker-compose file. It informs GitLab of your Tailnet name which will be used to access GitLab. Note that we are using port 8929 for accessing GitLab (just cm3588.your-tailnet.ts.net accesses OMV).
services:
gitlab:
image: yrzr/gitlab-ce-arm64v8:latest
container_name: gitlab
restart: always
hostname: 'your-hostname'
environment:
GITLAB_OMNIBUS_CONFIG: |
letsencrypt['enable'] = false
external_url 'https://cm3588.your-tailnet.ts.net:8929'
gitlab_rails['gitlab_shell_ssh_port'] = 2424
ports:
- '8929:8929'
- '443:443'
- '2424:22'
volumes:
- '${PATH_TO_APPDATA}/config:/etc/gitlab'
- '${PATH_TO_APPDATA}/logs:/var/log/gitlab'
- '${PATH_TO_APPDATA}/data:/var/opt/gitlab'
shm_size: '256m'
Save the file and start it by clicking "Up". We are only starting the container now for GitLab to initialize the persistent files and directories. Note that it will take a while for GitLab to initialize. When it is done stop it by pressing "Down".
We must now generate HTTPS certificates using Tailscale. SSH into the CM3588 and run tailscale cert
. When it is done you should see two files:
cm3588.your-tailnet.ts.net.crt
cm3588.your-tailnet.ts.net.key
We must now pass these to GitLab.
Move them to GitLabs /etc/config/ssl
folder. The actual directory using the compose file above should be /srv/dev-disk-by-uuid-UUID/config/ssl
.
Start the GitLab container again by pressing "Up". With any luck you should now be able to access GitLab with Tailscale using the address https://cm3588.your-tailnet.ts.net:8929
.
You must now login as admin and configure GitLab to your liking, adding users etc.. GitLab autogenerates a admin password located in a file in the appdata/config
folder. Note that this file is automatically deleted after 24 hours.
Note that the HTTPS certificates expire after 90 days. After which you must generate them again and replace the expired ones.
It was very important to me that i could get glab working on all of my machines for interfacing with the CM3588 GitLab instance. glab is a command-line tool that allows quick and easy repo management. It also, importantly, allows you to script your way of of tedious repo tasks using your favorite scripting language (e.g. Python).
Login in to your GitLab user. Click on your profile icon and go to Preferences > Access Tokens. Add a new token in the "api" and "write_repository" scopes. Save the token.
Install glab on your device. My preferred method of installation is using a package manager
choco install glab
Now we must login with glab
glab auth login --hostname cm3588.your-tailnet.ts.net:8929
- Login using token (the one you just saved).
- Use HTTPS as default git protocol.
- Authenticate Git with GitLab credentials (yes).
- Use HTTPS as host API protocol.
You should be logged in as your GitLab user. You can use glab to create, delete and configure your repos.
By default GitLab will consume quite a lot of ram. If the GitLab server is for private use you can reduce the amount of workers without any performance loss. In /srv/dev-disk-by-uuid-UUID/config/gitlab.rb
uncomment and adjust the following:
puma['worker_processes'] = 0
prometheus_monitoring['enable'] = false
postgresql['shared_buffers'] = "256MB"
This reduces the ram usage to just under 2GB.
The CM3588 is extremely capable at video transcoding due to the integrated GPU. Jellyfin can easily be hosted on system alongside GitLab in another Docker container.
First we must install drivers for the Mali GPU. They are hosted on GitHub link. Download the latest using wget
:
wget https://github.com/tsukumijima/libmali-rockchip/releases/download/v1.9-1-3238416/libmali-valhall-g610-g13p0-gbm_1.9-1_arm64.deb
Install using dpkg:
dpkg -i libmali-valhall-g610-g13p0-gbm_1.9-1_arm64.deb
In the Docker global environment file we add the paths to where we want to store Jellyfin cache and configuration, as well as the path to our media. I choose the media path to be a folder on the SMB share.
JELLYFYN_CONFIG=/srv/<path>
JELLYFIN_CACHE=/srv/<path>
PATH_TO_MEDIA=/srv/<path>
Next use the following Docker compose file:
services:
jellyfin:
image: 'ghcr.io/jellyfin/jellyfin:10.9.10'
container_name: 'jellyfin'
ports:
- '8096:8096/tcp'
security_opt: true
- systempaths=unconfined
- apparmor=unconfined
group_add:
- 44 # video group
devices:
- '/dev/dri:/dev/dri'
- '/dev/dma_heap:/dev/dma_heap'
- '/dev/mali0:/dev/mali0'
- '/dev/rga:/dev/rga'
- '/dev/mpp_service:/dev/mpp_service'
volumes:
- '${JELLYFIN_CONFIG}:/config'
- '${JELLYFIN_CACHE}:/cache'
- '${PATH_TO_MEDIA}:/media'
restart: unless-stopped
Now start the container. Jellyfin should be available on port 8096. When Jellyfin is set up remember to enable hardware transcoding.