TechOpt https://www.techopt.io/ Programming, servers, Linux, Windows, macOS & more Sat, 24 Oct 2026 20:34:39 +0000 en-US hourly 1 https://wordpress.org/?v=7.1.4 https://www.techopt.io/wp-content/uploads/2024/07/cropped-logo-1-32x32.png TechOpt https://www.techopt.io/ 32 32 Host an openSUSE RPM Repository With Gitea and zypper https://www.techopt.io/linux/host-an-opensuse-rpm-repository-with-gitea-and-zypper https://www.techopt.io/linux/host-an-opensuse-rpm-repository-with-gitea-and-zypper#respond Fri, 23 Oct 2026 01:19:20 +0000 https://www.techopt.io/?p=1498 I run a self-hosted openSUSE RPM repository using my existing Gitea instance. This allows me to install and update third-party software through zypper on both openSUSE Leap and Tumbleweed, without manually downloading RPM files on every machine. The repository uses Gitea’s built-in package registry to store and sign RPM packages. An hourly systemd job checks […]

The post Host an openSUSE RPM Repository With Gitea and zypper appeared first on TechOpt.

]]>
I run a self-hosted openSUSE RPM repository using my existing Gitea instance. This allows me to install and update third-party software through zypper on both openSUSE Leap and Tumbleweed, without manually downloading RPM files on every machine.

The repository uses Gitea’s built-in package registry to store and sign RPM packages. An hourly systemd job checks upstream for newer releases, publishes them to Gitea, and removes older versions automatically.

Currently, I’m using this setup to distribute Cursor, but it can work with other software distributed as RPM packages as well.

In this guide, I’ll explain how the repository works, how to configure Gitea and zypper, and how I keep the packages up to date.

How the openSUSE RPM Repository Works

Gitea 1.20 and newer includes a built-in RPM package registry that supports the rpm-md repository format used by package managers such as yum, dnf, and zypper.

This means you can host an RPM repository directly from Gitea without running a separate package server or generating repository metadata yourself.

When I upload an RPM, Gitea stores the package in its package registry and automatically regenerates the repository’s repodata.

The general setup is straightforward:

  1. An automated job checks whether a newer upstream RPM is available.
  2. If a new build exists, the job downloads the RPM and uploads it to Gitea.
  3. Gitea signs the package and updates the repository metadata.
  4. openSUSE clients access the repository using zypper.
  5. The publisher keeps the two newest versions of each package and deletes older ones.

The important distinction is that I’m not compiling software specifically for openSUSE.

Instead, I’m mirroring upstream RPMs that are already compatible with the distributions I’m using. This is not an openSUSE Build Service project, and it doesn’t involve rebuilding packages from RPM spec files.

One Repository for Leap and Tumbleweed

My Gitea RPM registry uses a single group named opensuse.

Both Leap and Tumbleweed access that same group, so I don’t need separate repositories for each distribution.

For this guide, I’ll use the following example configuration:

SettingValue
Gitea URLhttps://git.example.com
Package ownerpackages
Repository groupopensuse
Repository typerpm-md
Architecturex86_64
Packagecursor

The resulting repository URL is:

https://git.example.com/api/packages/packages/rpm/opensuse

Notice that packages appears twice in the URL. The first occurrence belongs to Gitea’s package API path, while the second is the name of the package owner.

All hostnames, usernames, and credentials shown in this guide are placeholders.

Is a Fedora RPM Compatible With openSUSE?

Cursor distributes an RPM intended for RPM-based Linux distributions, including Fedora-compatible systems.

At the time I configured this repository on September 26, 2026, its upstream x86_64 RPM was:

cursor-3.22.7-1790228250.el8.x86_64

The file was approximately 290 MB.

Despite the .el8 suffix, this particular RPM works on both openSUSE Leap and Tumbleweed.

Its dependencies consist primarily of shared library sonames, along with ca-certificates and xdg-utils. There are no Fedora-specific package names in its RPM Requires metadata.

Additionally, its highest required glibc symbol is GLIBC_2.28, which is available on openSUSE Leap 15.3 and newer, as well as Tumbleweed.

I’ve used the same RPM successfully on Leap 15.6 and Tumbleweed, including its GTK and NSS dependencies.

Of course, this doesn’t mean every Fedora RPM will work on openSUSE. You still need to inspect the dependencies of any additional packages you mirror.

1. Configure Gitea to Host RPM Packages

First, you’ll need an existing Gitea installation with its package registry enabled.

For RPM publishing, Gitea 1.20 or newer is required. However, you’ll need Gitea 1.23 or newer to use its RPM signing functionality.

You can find more details about the supported endpoints in the official Gitea RPM package registry documentation.

Configure the Reverse Proxy Upload Limit

One important consideration is the upload size.

Since Cursor’s RPM was approximately 290 MB at the time of setup, the reverse proxy in front of Gitea needs to accept request bodies larger than the package.

For example, if you’re using nginx, you can configure:

client_max_body_size 512m;

Adjust this value to accommodate the RPMs you intend to publish.

If the proxy rejects the upload with HTTP 413 Request Entity Too Large, the request body limit is probably too low.

You’ll also want enough storage for multiple package versions. Keeping two copies of Cursor requires approximately 600 MB, excluding additional registry overhead.

Create a Package Access Token

The publisher needs a Gitea personal access token with the following permissions:

  • read:package
  • write:package

This token allows the publishing job to upload packages, inspect existing versions, and delete older ones.

The publishing token should remain on the machine running the synchronization job. It doesn’t need to be distributed to openSUSE clients.

If the Gitea package owner is public, clients can access the RPM repository without authentication.

For private package owners, I’ll cover how to configure a separate read-only token later.

2. Upload and Sign an RPM Package

With Gitea configured, the next step is publishing an RPM.

Gitea’s RPM registry accepts HTTP PUT requests containing the RPM file.

For example:

curl --user USER:TOKEN --upload-file cursor.rpm \
  "https://git.example.com/api/packages/packages/rpm/opensuse/upload?sign=true"

The --upload-file option tells curl to upload the RPM using an HTTP PUT request.

The sign=true query parameter tells Gitea to sign the RPM as part of the publishing process.

This is particularly important for Cursor because its upstream RPM is not signed.

Gitea’s generated repository configuration enables gpgcheck=1, meaning zypper expects a valid package signature. Without signing, installation can fail during package verification.

Enable RPM Signing by Default

Alternatively, you can enable automatic RPM signing globally through Gitea’s app.ini.

Under an uncommented [packages] section, add:

[packages]
DEFAULT_RPM_SIGN_ENABLED = true

With this enabled, Gitea signs RPM uploads by default instead of requiring sign=true on every request.

I use signing so clients can verify packages against the key associated with the Gitea package owner.

Understanding Upload Responses

The RPM upload endpoint returns different HTTP status codes depending on the result.

StatusMeaning
201 CreatedRPM published successfully
409 ConflictThat exact package version already exists
400 Bad RequestThe submitted package is invalid

When Gitea returns 201, it also regenerates the group’s repository metadata.

A 409 isn’t necessarily a problem. In this setup, it simply means the same package version already exists, so there’s nothing to replace.

There is no reason to delete and reupload an identical version.

3. Import the Gitea RPM Signing Key on openSUSE

Before installing packages from the repository, clients need to trust the public key used by Gitea to sign them.

Each Gitea package owner has its own signing key.

For the example owner, the public key URL is:

https://git.example.com/api/packages/packages/rpm/repository.key

However, there’s an important detail: Gitea doesn’t serve this key in the ASCII-armored format expected by the usual rpm --import workflow.

Instead, I import the key with GnuPG, export an armored copy, and then import that copy into RPM.

Run the following commands in a root shell, such as one opened with sudo -i:

curl -fsS -o repository.key \
  "https://git.example.com/api/packages/packages/rpm/repository.key"

gpg --batch --import repository.key

gpg --batch --export --armor > /etc/pki/rpm-gpg/gitea-packages-opensuse.asc

rpm --import /etc/pki/rpm-gpg/gitea-packages-opensuse.asc

The result is an armored public key at:

/etc/pki/rpm-gpg/gitea-packages-opensuse.asc

I’ll reference this file in the zypper repository configuration.

If you publish RPMs under another Gitea owner, you’ll need to import that owner’s signing key instead.

4. Configure the Repository in zypper

The client configuration is almost identical on openSUSE Leap and Tumbleweed.

Before adding the repository, there’s one setting I recommend applying to avoid problems when downloading large RPMs.

Configure zypper’s Temporary Directory

On some openSUSE installations, /tmp resides on a separate tmpfs filesystem.

When zypper downloads a package into that temporary location and attempts to rename it into /var, the operation can fail if the directories reside on different filesystems.

To avoid this, I use /var/tmp as the temporary directory.

export TMPDIR=/var/tmp
mkdir -p "$TMPDIR"

Run these commands before invoking zypper in the same shell. If you’re using a root shell, keep that shell open for the installation commands.

This avoids the cross-filesystem rename problem without disabling package verification or changing the repository itself.

Option A: Configure a Private Gitea Repository

My Gitea package owner is private, so the openSUSE clients need authentication to download repository metadata and packages.

I don’t put the access token directly into the repository URL.

Instead, I store a separate read-only token in zypper’s credentials directory.

Create the directory and credentials file:

install -d -m 700 /etc/zypp/credentials.d

umask 077

cat > /etc/zypp/credentials.d/gitea-packages-opensuse <<'EOF'
username=USER
password=READ_TOKEN
EOF

chmod 600 /etc/zypp/credentials.d/gitea-packages-opensuse

Replace USER and READ_TOKEN with a Gitea user and a token authorized to read packages from that owner.

This should not be the same token used by the publisher, since clients don’t need permission to upload or delete packages.

Next, create the repository configuration file:

/etc/zypp/repos.d/gitea-packages-opensuse.repo

Add the following:

[gitea-packages-opensuse]
name=packages openSUSE
baseurl=https://git.example.com/api/packages/packages/rpm/opensuse?credentials=gitea-packages-opensuse
enabled=1
autorefresh=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/gitea-packages-opensuse.asc
type=rpm-md

Notice the ?credentials=gitea-packages-opensuse parameter in the baseurl.

This tells libzypp to load credentials from the matching file in /etc/zypp/credentials.d, rather than embedding them directly in the repository configuration.

You can read more about this feature in the official libzypp configuration documentation.

Now refresh the repository:

zypper --non-interactive --gpg-auto-import-keys refresh gitea-packages-opensuse

Then install Cursor:

zypper --non-interactive install --allow-vendor-change cursor

The --allow-vendor-change flag permits zypper to install or replace the package from this repository even when the package vendor differs from another installed version.

Once installed, I can update Cursor using:

zypper refresh && zypper update cursor

That’s all the client needs. It can now use the private Gitea package registry like another RPM repository.

Option B: Configure a Public Gitea Repository

If your Gitea package owner is public, the setup is simpler.

You don’t need to create a credentials file.

After importing the signing key from the previous section, you can add the repository directly:

zypper addrepo https://git.example.com/api/packages/packages/rpm/opensuse.repo

Then refresh and install:

zypper refresh
zypper install cursor

Remember to set TMPDIR=/var/tmp before installing.

If the generated repository file points directly to Gitea’s raw signing key, replace its gpgkey value with the local armored key:

gpgkey=file:///etc/pki/rpm-gpg/gitea-packages-opensuse.asc

After that, the public and private configurations behave the same way from the client’s perspective.

Both Leap and Tumbleweed use the same Gitea repository and receive the same RPM.

screenshot of cursor rpm package in opensuse rpm gitea repository
A screenshot of the Cursor RPM package in the Gitea packages interface.

5. Automatically Detect and Publish Cursor Updates

Manually uploading RPMs works, but I want the repository to stay current without having to check for releases myself.

I use a publishing job that runs once per hour.

The important part is detecting when a new RPM is available.

Find Cursor’s Latest RPM

Cursor exposes a download endpoint for its latest Linux x86_64 RPM:

https://api2.cursor.sh/updates/download/golden/linux-x64-rpm/cursor/latest

This endpoint redirects to the actual RPM download.

I use the redirect’s Location header to identify a new build.

You can inspect the redirect using:

curl -fsSI \
  "https://api2.cursor.sh/updates/download/golden/linux-x64-rpm/cursor/latest"

The resulting download URL contains a production commit identifier in a path resembling:

production/<commit>/

For example, on September 26, 2026, the latest download pointed to a build associated with this commit:

37076c6c3f9e253c0fa2305197e45befd13a2268

My publisher saves that commit identifier in a state file.

The next time it runs, it compares the current redirect against the saved identifier. If nothing changed, the job exits without downloading the entire RPM again.

This is especially useful for a package of approximately 290 MB.

Why I Use the Golden Download URL

Cursor also has a JSON-based update API, but it doesn’t accept the linux-x64-rpm platform identifier.

Instead of polling an unsupported platform through that API, I use the golden download endpoint.

It’s also important to use the URL ending in /cursor/latest, rather than one pinned to a specific release line such as /cursor/3.22.

A version-specific URL might receive updates within the 3.22 series but miss the next minor release.

The latest endpoint is what allows the publisher to keep following new versions.

How the Publishing Job Works

My hourly job follows five steps.

1. Check the upstream redirect

It sends a HEAD request to the golden download URL and extracts the commit identifier from the Location header.

2. Compare against the saved state

Each package has its own state file containing the identifier of its last successfully published build.

If the identifier matches, there’s nothing new to publish.

3. Download and inspect the RPM

When the identifier changes, the job downloads the RPM and reads the package metadata using rpm.

For example:

rpm -qp --nosignature \
  --queryformat '%{NAME}\n%{VERSION}-%{RELEASE}\n%{ARCH}\n' \
  cursor.rpm

This provides the package name, version-release, and architecture.

For the example Cursor RPM from September 2026, those values correspond to:

cursor
3.22.7-1790228250.el8
x86_64

4. Upload the new build

The job publishes the RPM to the opensuse group using Gitea’s upload endpoint with sign=true.

curl --user USER:TOKEN --upload-file cursor.rpm \
  "https://git.example.com/api/packages/packages/rpm/opensuse/upload?sign=true"

A successful upload returns 201, and Gitea regenerates the repository metadata.

After a successful publication, the job saves the new commit identifier to that package’s state file.

5. Remove older package versions

Finally, the publisher checks which versions are already stored in Gitea and keeps the two newest.

This allows me to retain one previous build without storing an unlimited number of RPMs.

Keep Only the Two Newest RPM Versions

Gitea exposes a REST API for retrieving the existing package versions.

For Cursor, the endpoint is:

GET /api/v1/packages/packages/rpm/cursor?limit=50

The publisher retrieves the version list and sorts the entries by created_at, newest first.

It keeps the first two versions and deletes everything older.

The delete endpoint uses the package name, version-release, and architecture:

curl --user USER:TOKEN -X DELETE \
  "https://git.example.com/api/packages/packages/rpm/opensuse/package/cursor/VERSION-RELEASE/x86_64"

For example, the version-release of the September 2026 package was:

3.22.7-1790228250.el8

Gitea returns 204 No Content when the deletion succeeds.

A 404 means the package version was already removed, while other unexpected responses indicate a failure that the job should report.

Keeping only two versions limits Cursor’s RPM storage to roughly 600 MB at the package sizes I was seeing when I configured this setup.

6. Schedule Automatic Updates With a systemd Timer

To run the publisher automatically, I use a systemd user service and timer on an always-on Linux machine.

This avoids needing a Gitea Actions runner or another CI system just to keep an RPM repository updated.

Configure the Publisher Environment

The publisher reads its Gitea credentials and repository settings from an environment file.

The file contains the following values:

GITEA_URL=https://git.example.com
GITEA_OWNER=packages
GITEA_USER=USER
GITEA_TOKEN=TOKEN
GITEA_GROUP=opensuse
KEEP=2

GITEA_GROUP defaults to opensuse, while KEEP defaults to 2.

I keep this file private using permissions of 600, since it contains the token with package publishing access.

The client-side read token is separate and isn’t required by the publisher.

Create the systemd Service

Create the following user service:

~/.config/systemd/user/opensuse-rpm-sync.service

Add:

[Unit]
Description=Publish vendor RPMs to the Gitea openSUSE repository
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
EnvironmentFile=%h/.config/opensuse-rpm/env
ExecStart=%h/bin/sync-opensuse-rpm.sh
Nice=10

The ExecStart value points to the local publishing script. Adjust it to wherever you keep your own publisher.

The service uses Type=oneshot, meaning systemd runs the synchronization and considers the service complete when the script exits.

I’ve also set Nice=10 to give the job a lower scheduling priority than normal interactive processes.

Create the Hourly Timer

Next, create:

~/.config/systemd/user/opensuse-rpm-sync.timer

With the following configuration:

[Unit]
Description=Hourly openSUSE RPM sync

[Timer]
OnCalendar=hourly
Persistent=true
RandomizedDelaySec=5min

[Install]
WantedBy=timers.target

There are two useful settings here.

Persistent=true tells systemd to trigger a missed scheduled run after the machine becomes available again.

Meanwhile, RandomizedDelaySec=5min introduces a small random delay so the job doesn’t necessarily start at the exact beginning of every hour.

Hourly checks are sufficient for the software I’m mirroring.

Enable the Timer

Reload the user systemd configuration and enable the timer:

systemctl --user daemon-reload
systemctl --user enable --now opensuse-rpm-sync.timer

I also enable user lingering:

loginctl enable-linger "$USER"

This allows the user systemd instance to continue running even when the account isn’t actively logged in.

At this point, the timer runs the publishing job automatically without requiring a desktop session or an interactive terminal.

7. Add More RPM Packages to the Same Repository

Although I currently use this repository for Cursor, the same approach works for additional vendor RPMs.

There’s no need to create a new Gitea package group or add another repository on the openSUSE clients.

Instead, the publisher uses a separate source definition for each package.

Every published RPM appears in the existing opensuse group.

Cursor’s Source Configuration

For Cursor, the source definition looks like this:

NAME=cursor
KIND=redirect
URL=https://api2.cursor.sh/updates/download/golden/linux-x64-rpm/cursor/latest
STATE_REGEX=.*/production/\([^/]*\)/.*
KEEP=2

The redirect source type sends a HEAD request to the URL and uses the redirect destination as the identity.

The optional STATE_REGEX extracts a specific identifier from that URL.

In Cursor’s case, it extracts the production commit.

If the regular expression doesn’t match the redirect, the publisher treats that as an error rather than blindly downloading and publishing an unexpected file.

Supported Source Types

My publisher handles three different types of package sources.

Source typeHow changes are detected
redirectHEAD request and redirect Location, optionally processed by STATE_REGEX
urlETag, Last-Modified, and Content-Length headers, with SHA256 fallback
fileSHA256 checksum of a local RPM

For a direct URL, the publisher combines the available HTTP metadata into an identity.

If the server provides none of those headers, the publisher downloads the file and computes its SHA256 checksum instead.

For a local file, the checksum serves as the identity from the beginning. If the file doesn’t exist, the job reports a failure.

Example: Add a Second Package

Suppose I have another application distributed through a direct RPM download.

Its source definition could look like this:

NAME=example
KIND=url
URL=https://example.com/example-latest.x86_64.rpm
KEEP=2

The next sync checks this source along with Cursor.

Each package maintains a separate state file, using its package name as the filename. For example, the files could live under a state directory such as:

~/.local/state/opensuse-rpm/

Keeping separate state files prevents an update to one package from affecting change detection for another.

The publisher also processes sources independently. If one source fails, it continues processing the others, but the overall job still exits with a failure status.

Once the additional package is uploaded, it becomes available through the same Gitea repository.

On an openSUSE client, I can install it using:

zypper install example

No additional .repo file is necessary.

Adding the repository and refreshing its metadata does not automatically install every package it contains. Clients still choose which packages to install.

8. Troubleshooting Common Problems

There are a few issues worth checking if the repository doesn’t behave as expected.

HTTP 413 When Uploading an RPM

If the upload returns:

413 Request Entity Too Large

Check the request body size limit on the reverse proxy in front of Gitea.

For nginx, this is controlled by client_max_body_size.

Remember that the limit must accommodate the full RPM file, not just a small metadata request.

zypper Rejects the Package Signature

Check that Gitea signed the RPM during upload.

Cursor’s upstream RPM is unsigned, while the generated repository enables gpgcheck=1.

Make sure you’re using sign=true or have enabled DEFAULT_RPM_SIGN_ENABLED in Gitea.

Also verify that you’ve imported the public key belonging to the correct Gitea package owner.

If rpm --import rejects the raw repository.key, convert it to an ASCII-armored key using the GnuPG steps earlier in this guide.

Don’t disable package signature verification just to work around an incorrectly configured repository.

Private Repository Refresh Fails

If zypper refresh can’t read the repository metadata, verify the credentials file.

Check that:

  • The token has package read access.
  • The ?credentials= value matches the credentials filename.
  • The file is stored under /etc/zypp/credentials.d.
  • The file contains the correct username and password fields.

For private owners, an anonymous refresh won’t have permission to retrieve the package metadata.

Downloads Fail When Moving the RPM

If zypper reports an error while renaming or moving a downloaded package, check whether /tmp and /var reside on different filesystems.

Use:

export TMPDIR=/var/tmp
mkdir -p "$TMPDIR"

Then retry the zypper operation from the same shell.

Cursor Updates Aren’t Being Detected

First, make sure the publisher checks the golden URL ending in:

/cursor/latest

A URL pinned to a specific release line can miss newer minor releases.

Next, inspect the redirect using curl -fsSI and confirm that the Location header contains the expected production commit.

Also check the package’s saved state file and the systemd service logs to confirm the hourly job actually ran.

Multiple Repositories Provide Cursor

If you’ve installed dnf, check whether Cursor’s RPM created:

/etc/yum.repos.d/cursor.repo

I remove this file to avoid maintaining a second Cursor package source through its upstream yum repository.

You can also inspect your enabled zypper repositories using:

zypper lr

And verify the installed Cursor RPM with:

rpm -q cursor

The installed package name and version should correspond to the RPM published through Gitea.

Conclusion

Using Gitea as an openSUSE RPM repository gives me a straightforward way to distribute third-party packages across multiple Linux machines without maintaining a separate package server.

Gitea already handles RPM storage, package signing, and repository metadata, while zypper takes care of installation and dependency resolution on the clients.

The hourly publisher handles the remaining work: detecting upstream releases, downloading new RPMs, publishing signed packages, and keeping the number of stored versions under control.

The result is a single repository shared between Leap and Tumbleweed, with no need to manually download Cursor’s RPM every time a new build becomes available.

If you’re maintaining several openSUSE installations, I’ve also written guides covering upgrading openSUSE Leap from 15.5 to 15.6 and upgrading openSUSE Leap 15.6 to 16.0.

For additional package management references, you can also check out the tools available on TechOpt.

The post Host an openSUSE RPM Repository With Gitea and zypper appeared first on TechOpt.

]]>
https://www.techopt.io/linux/host-an-opensuse-rpm-repository-with-gitea-and-zypper/feed 0
The Auto-Tune Algorithm: Science and Engineering https://www.techopt.io/music-production/the-auto-tune-algorithm-science-and-engineering https://www.techopt.io/music-production/the-auto-tune-algorithm-science-and-engineering#respond Wed, 14 Oct 2026 00:17:32 +0000 https://www.techopt.io/?p=1155 The Auto-Tune algorithm has revolutionized modern music. Like it or not, what started as a niche studio tool for subtle pitch correction has become a defining sound of the 21st century. Originally developed by Antares Audio Technologies and released in the late 1990’s, Auto-Tune was the first software to correct pitch in real-time. Today, competitors […]

The post The Auto-Tune Algorithm: Science and Engineering appeared first on TechOpt.

]]>
The Auto-Tune algorithm has revolutionized modern music. Like it or not, what started as a niche studio tool for subtle pitch correction has become a defining sound of the 21st century. Originally developed by Antares Audio Technologies and released in the late 1990’s, Auto-Tune was the first software to correct pitch in real-time.

Today, competitors like Melodyne, Waves Tune, and integrated DAW solutions like Logic Flex Pitch exist. Underneath all the branding, every system follows the same core signal-processing principles pioneered by the original Auto-Tune algorithm.

Everyone these days uses pitch correction on vocals, at least in the studio, and often live too. Even if you think your favourite band or artist doesn’t, they more than likely do. If they say they don’t, they’re most likely lying or aren’t even aware their audio engineers have applied it! It doesn’t have to sound robotic when done properly. It can sound perfectly natural to the untrained ear, especially when done manually with Auto-Tune in graphical mode or Melodyne.

As a computer engineer with a passion for music production, I’ve always been fascinated by how pitch correction algorithms work at a technical level. That’s what I’m going to be explaining in this article.

A Brief History of the Auto-Tune Algorithm

The original Auto-Tune was invented in 1997 by Dr. Andy Hildebrand, a former Exxon engineer and signal-processing expert. Hildebrand had worked on seismic data interpretation, detecting echoes from underground structures, before applying similar mathematical principles to human voice analysis.

The first commercial release, Auto-Tune by AnTares Systems, revolutionized recording studios. Engineers could now correct a singer’s pitch automatically, transparently, and in real time.

Screenshots of the original auto-tune in both automatic and graphical mode
Screenshots of the original Antares Auto-Tune in both automatic and graphical mode, taken from the original Auto-Tune user manual and kept as a preservation copy of the original Auto-Tune manual.

The algorithm became famous, and in some cases infamous, after Cher’s 1998 hit Believe. Auto-Tune was not used in this song so much to hide imperfections, as it was cranked all the way up to be used as an effect. Cher’s producers tried hiding how they created the effect by saying it was a vocoder, but other engineers eventually figured out that the effect was produced by cranking Auto-Tune to the max. This effect is now more commonly known as the Cher or T-Pain effect.

Despite new user interfaces, new features added to both automatic and manual correction options, competitor offerings and neural enhancements, all pitch correction software still follows the same fundamental engineering principles established by the original Auto-Tune algorithm.

Screenshot of Auto-Tune Pro 11 in automatic and graphical mode, released 2024
Screenshots of the modern Auto-Tune interface in both automatic and graphical mode, from Auto-Tune Pro 11 released in 2024. Taken from the Auto-Tune Pro 11 user guide and kept as a preservation copy of the Auto-Tune Pro 11 user guide.

How Does the Auto-Tune Algorithm Work?

I’m going to break the Auto-Tune algorithm into three parts: pitch detection, pitch correction, and formant correction.

Formant correction is an optional last step, but is included enabled by default in most pitch correction software these days. It’s a necessary step to prevent chipmunk-like distortion for more drastic pitch adjustments after the pitch correction step, although it can introduce additional artifacts as explained below.

Pitch Detection

A sung note is a repeating waveform. Its pitch is the number of repetitions per second, or fundamental frequency. If we know the length of one repetition in audio samples, the conversion is simple:

frequency = sample rate / period

A4 at 440 Hz repeats roughly every 2.27 milliseconds, or every 109 samples at 48 kHz. Sing flat and the period gets longer. Sing sharp and it gets shorter. Measuring that period is the first job of the Auto-Tune algorithm.

The obvious first approach is a Fast Fourier Transform (FFT). But an FFT gives us a stack of frequencies, not necessarily the pitch. A voice has a fundamental and harmonics at multiples of that frequency. Depending on the vowel, the fundamental can be weak or even missing.

Picking the tallest FFT bin is the wrong pitch detector. It may identify a harmonic instead of the note. There is also a resolution tradeoff: at 48 kHz, a 1,024-sample FFT has bins about 46.9 Hz apart. A 4,096-sample window improves that to 11.7 Hz, but spans 85 milliseconds, potentially blurring fast note changes.

Autocorrelation and YIN

A better approach is autocorrelation, the idea Hildebrand brought over from seismology. Slide a copy of a short waveform against itself and measure where the copies line up. The offset is the lag. If the signal repeats every 109 samples, there should be a strong match at a lag of about 109.

Diagram showing how autocorrelation detects vocal pitch by identifying repeating waveform patterns, using A4 at 440 Hz with a period of 2.27 milliseconds.
Autocorrelation-based pitch detection. The top graph shows a repeating vocal waveform, while the bottom graph shows its autocorrelation, with peaks at regular intervals. The first significant peak after zero lag identifies the fundamental period (2.27 ms for A4 at 440 Hz), allowing the algorithm to calculate the vocal pitch.

We can calculate autocorrelation efficiently with an FFT. Take the transform, square its magnitudes to obtain the power spectrum, then run an inverse FFT. This is the Wiener-Khinchin relationship. Proper window handling and zero-padding avoid mistaking circular wraparound for a real repetition. The FFT is calculating periodicity, not picking the loudest frequency.

YIN, described by Alain de Cheveigné and Hideki Kawahara in 2002, is a useful refinement. For every candidate lag, it sums the squared differences between two shifted sections of the signal. A small result means they match. With the appropriate energy terms, we can derive this difference efficiently from the autocorrelation already calculated.

YIN converts these values into a cumulative mean normalized difference curve, making pitch detection more robust and avoiding the meaningless perfect match at lag zero. The tracker walks through the candidate periods until the curve passes below a threshold, then finds the bottom of the local dip. A deep dip indicates a convincingly repeating waveform.

Diagram illustrating YIN pitch detection using a cumulative mean normalized difference function (CMNDF) to identify the fundamental frequency of A4 at 440 Hz.
How the YIN pitch detection algorithm identifies the fundamental frequency. The top graph shows the difference function, with minima at repeating waveform periods. The bottom graph shows the cumulative mean normalized difference function (CMNDF), where the first reliable dip below the detection threshold identifies the fundamental period (2.27 ms for A4 at 440 Hz). Selecting this dip helps prevent octave detection errors caused by later minima.

The true period rarely lands on a whole sample. Fitting a parabola around that dip gives a fractional estimate, such as 109.1 samples rather than 109. That precision matters: small period errors translate into audible tuning errors. The depth of the dip also gives the tracker a confidence measure.

Avoiding Octave Errors and False Detections

Not every sound has a pitch. A vowel is relatively periodic; an “s”, breath, or other noisy consonant is not. If nothing passes the threshold, the detector should label the frame unvoiced and leave it alone rather than inventing a note.

A repeating waveform also matches at twice and three times its period, creating tempting extra dips. Choose the wrong one and the detected pitch jumps an octave. A robust tracker prefers the first reliable dip, checks half-period and double-period candidates, and compares nearby frames. A short median filter can eliminate isolated jumps.

Auto-Tune’s Tracking knob relates to that decision. It controls how much variation the plugin tolerates before rejecting a signal as non-periodic. A relaxed setting can help with breathy vocals; a stricter one rejects noise. The search range matters too: a bass note needs a longer window than a high tenor note.

Input Type helps the Auto-Tune algorithm identify pitch more accurately by selecting processing settings optimized for the expected vocal range or instrument. Auto-Tune Pro 11 offers Soprano, Alto/Tenor, Low Male, Instrument, and Bass Instrument options.

From an engineering perspective, different pitch ranges require different analysis parameters. For example, lower frequencies have longer waveform periods, so detecting a bass note requires a longer analysis window than detecting a soprano note. Selecting the appropriate Input Type helps the algorithm track the fundamental frequency more reliably and reduces the likelihood of pitch detection errors.

The detector ultimately outputs frequency in Hz, period in samples, and a voiced/unvoiced decision, updated many times a second. Graphical mode can display the resulting pitch curve on a piano roll. Automatic mode sends the estimate straight into correction.

Pitch Correction

We convert frequency into a musical note. MIDI note 69 is A4 at 440 Hz. Pitch errors are measured in cents, with 100 cents per semitone. A singer might be 30 cents flat, but the Auto-Tune algorithm doesn’t have to apply all 30 cents of correction immediately.

The target usually comes from the selected key and scale. Chromatic mode allows every semitone; C major allows C, D, E, F, G, A, and B. The nearest allowed pitch becomes the target. Scale controls can also remove notes as targets or mark them as Bypass, so they pass through without correction.

Retune Speed controls how fast the output moves toward that target, measured in milliseconds. Slower settings preserve little slides, overshoots, and drifts before the pitch settles. That’s why moderate correction can be almost impossible to hear.

Set Retune Speed to zero and that smoothing essentially disappears. Each new target is applied immediately, turning slides into steps between allowed notes.

That’s the robotic Cher or T-Pain sound from earlier. It isn’t a separate effect: it’s the same correction decision with almost no transition time.

Screenshot of Antares Auto-Tune Pro showing the auto-tune algorithm controls in Auto Mode, including Retune Speed, Flex-Tune, Humanize, Natural Vibrato, Tracking, Input Type, Key, and Scale.
The Auto Mode interface of Antares Auto-Tune Pro, showing the main controls used for automatic vocal pitch correction. Retune Speed determines how quickly notes are corrected, while Flex-Tune, Humanize, and Natural Vibrato help control how natural the performance sounds. Tracking and Input Type influence pitch detection, while Key and Scale determine which notes the algorithm targets.

Preserving Natural Expression

One of the biggest challenges with the Auto-Tune algorithm is correcting a singer’s pitch without removing the natural expression that makes a performance sound human. Real vocals contain small pitch variations, slides, and vibrato that aren’t necessarily mistakes. This is where controls like Flex-Tune, Humanize, and Natural Vibrato come into play.

Flex-Tune determines how much freedom a singer has to move between notes before pitch correction takes effect. At zero, Auto-Tune continuously pulls the detected pitch toward the nearest allowed scale note. Increasing Flex-Tune narrows the correction area around each target, allowing more natural slides, bends, and other intentional pitch variations to pass through. It changes how aggressively correction is applied, rather than how pitch is detected.

Humanize addresses a different problem. A fast Retune Speed might work perfectly for short notes, but it can make longer sustained notes sound unnaturally static by removing their natural pitch movement. Humanize solves this by applying a slower Retune Speed during the sustained portion of longer notes, while keeping the faster correction for shorter notes. This allows a vocal to stay tightly tuned without completely flattening its expression.

Natural Vibrato controls the depth of vibrato already present in the recording. Vibrato is the natural, periodic variation in pitch that occurs when a singer sustains a note. At its default setting of zero, Natural Vibrato neither increases nor decreases that variation. Negative values reduce the vibrato’s depth, while positive values exaggerate it.

These controls influence how the detected pitch is translated into a correction target over time. The result is a pitch-shifting ratio calculated as approximately 2^(cents/1200). Positive correction produces a ratio above 1, raising the pitch, while negative correction produces a ratio below 1, lowering it.

Graphical mode and Melodyne-style editing allow an engineer to draw or adjust the target manually instead of selecting it automatically. Either way, the waveform-shifting algorithm ultimately receives a target pitch ratio.

Screenshot of Antares Auto-Tune Pro in Graph Mode, showing the auto-tune algorithm's graphical pitch correction editor with detected vocal pitch curves, editable note targets, and the original audio waveform.
The Graph Mode interface of Antares Auto-Tune Pro, allowing engineers to manually adjust vocal pitch rather than relying entirely on automatic correction. The waveform appears behind the detected pitch curves, with green lines representing the original detected pitch and blue note regions representing correction targets. This allows precise adjustments to individual notes while preserving natural pitch variations, transitions, and vibrato.

TD-PSOLA

TD-PSOLA stands for Time-Domain Pitch-Synchronous Overlap-Add. This classic technique, described by Eric Moulines and Francis Charpentier, is a useful way to understand how real-time vocal pitch shifting can work. Commercial implementations are proprietary, and may use different or hybrid methods.

Using the period we already measured, we place an analysis mark near each repetition, sometimes called a pitch mark or epoch. Predict the next mark one period ahead, then adjust it by comparing a short section against the previous grain. Cross-correlation helps us line the cycles up in phase.

Poor alignment makes overlapping grains partially cancel, producing a hollow, metallic, comb-filtered sound. That’s why accurate marks matter just as much as accurate frequencies.

Around each mark, cut a grain about two periods long and apply a Hann window so the ends fade smoothly to zero. Place the grains onto a new output grid with spacing period / ratio. A ratio above 1 packs the marks closer and raises pitch; a ratio below 1 spreads them apart and lowers it.

Add overlapping grains together and divide by the accumulated window weights to prevent the loudness from pumping. The processor also needs enough buffering to assemble each grain. Real-time doesn’t mean zero latency, just a small, predictable delay.

The phrase keeps its original duration. Playing a recording faster would raise the pitch, shorten the phrase, and move all its resonances upward. TD-PSOLA rearranges existing cycles instead, preserving much of the singer’s character for modest shifts.

How TD-PSOLA reconstructs a pitch-corrected waveform. The top panel shows the original vocal waveform with pitch marks spaced by the original period T0. The middle panel shows short Hann-windowed grains extracted around each pitch mark. The bottom panel shows those grains overlap-added at a shorter target period, placing them closer together in time to raise the pitch while preserving the waveform’s natural structure.

An octave error from the detector means the shifter can receive incorrect pitch marks and grain lengths. Instead of reconstructing the voice, its overlaps start cancelling. Pitch detection and waveform shifting have to work as one system.

Phase Vocoder

Another common method is the phase vocoder. Instead of cutting the vocal into individual pitch periods, it works in the frequency domain. It splits audio into overlapping frames, applies an FFT to each one, and tracks the magnitude and phase of the frequency components. The idea is to reconstruct those components at different pitches while keeping the timing intact.

One way to do that is to stretch the audio without changing its pitch, then resample it back to its original duration. For example, stretch a four-second recording to eight seconds, then play that result at twice the speed. You get four seconds of audio again, but one octave higher. More advanced methods can move spectral peaks directly instead of using that two-stage process.

Diagram showing how a phase vocoder processes audio in the frequency domain using overlapping FFT analysis windows, a time-frequency representation, and phase-adjusted synthesis frames.
How a phase vocoder processes audio in the frequency domain. The top panel shows overlapping analysis windows applied to the input waveform before each frame is transformed with an FFT. The middle panel shows the resulting short-time Fourier transform (STFT), where each frame is represented by magnitude and phase across frequency bins. The bottom panel shows phase-adjusted synthesis frames being overlap-added back into the time domain.

The hard part is phase coherence. The FFT tells us both how strong each frequency is and where it sits in its cycle. If those phases don’t advance consistently between frames, the components no longer recombine cleanly. On an exposed vocal, this can produce a thin, metallic, distinctly phasey sound. In my experience, getting truly transparent results with a basic phase vocoder is more difficult than with period-based shifting on a clean, monophonic voice. Longer analysis windows can also smear consonants and other quick transients.

A phase vocoder doesn’t need one clean repeating period, making it useful for chords and more complex material that would confuse TD-PSOLA. Modern versions use phase locking and transient handling to reduce artifacts, and can sound very good when implemented carefully. Neither method is automatically better. For a single real-time vocal, TD-PSOLA is an attractive approach; for polyphonic audio or larger transformations, a phase vocoder may be more practical.

Most commercial pitch correction software vendors don’t publicly document the exact signal-processing algorithms behind their products. However, from an engineering perspective, it’s reasonable to expect that monophonic, real-time vocal processors often favour pitch-synchronous techniques like TD-PSOLA, while polyphonic processors may rely on more complex frequency-domain techniques, including phase vocoders. Melodyne’s polyphonic mode, for example, uses Celemony’s proprietary DNA (Direct Note Access) technology to manipulate individual notes within chords. Although its exact implementation isn’t publicly documented, spectral analysis and resynthesis techniques are a natural approach to solving this more complex problem.

Formant Correction

Vocal cords create a harmonic-rich source. The throat, mouth, and nasal passages shape it into a spectral envelope. Its prominent resonances are called formants. They help distinguish an “ah” from an “ee” even when someone sings both at the same pitch. Harmonic spacing tells us pitch; the envelope tells us about the vocal tract.

TD-PSOLA preserves much of that envelope because each grain comes from the original voice. Small corrections therefore usually avoid the chipmunk effect. Naive resampling is different: speeding up the recording shifts both harmonics and formants, making the singer sound smaller and brighter.

Modelling the Vocal Tract with LPC

Large shifts, or deliberate changes in vocal character, benefit from an explicit source-filter model. One common approach is Linear Predictive Coding (LPC), which models the vocal tract as a filter separate from the excitation.

Take a short voiced frame and calculate its autocorrelation. Levinson-Durbin can then estimate coefficients for an all-pole filter. A voice-band model might use roughly 10 to 16 coefficients, depending on sample rate and analysis bandwidth. The filter approximates the resonances that give vowels their shape.

Inverse-filter the recording to remove much of that envelope. The residual is a buzzy approximation of the excitation. Shift its pitch, keep or warp the envelope independently, then combine them again. Keeping the envelope fixed helps retain the original voice; moving it changes the voice’s perceived size and tone.

Three-stage diagram showing how formant correction works in pitch correction algorithms, comparing the original vocal spectrum, upward-shifted formants, and corrected formants that preserve natural vocal resonance.
How formant correction preserves natural vocal characteristics during pitch shifting. The left graph shows the original voice, with harmonic spacing determining pitch and formant peaks (F1, F2, F3) shaping vocal timbre. The middle graph illustrates how shifting pitch upward without formant preservation can also shift these resonances higher, producing a brighter, chipmunk-like sound. The right graph shows formant correction restoring the resonances toward their original frequencies while maintaining the higher pitch, resulting in a more natural-sounding voice.

That explains Formant Correction and Throat Length. Formant Correction keeps vocal resonances from following large pitch shifts. A longer modelled throat lowers the formants for a deeper, darker sound; a shorter one raises them for a brighter, smaller voice. The chipmunk effect becomes something we can control deliberately.

When Formant Correction Causes Artifacts

Resynthesis must also match the grain’s energy and smoothly update the filter or envelope between frames. Otherwise the voice can click or change colour abruptly. Even careful modelling is only an approximation.

For small corrections with a neutral throat setting, I’d avoid additional formant processing when the shifter already preserves the voice. A model can create its own artifacts. Breath, doubled vocals, distortion, or polyphonic material can confuse its estimate, producing hollow, phasey or lispy results.

The voiced/unvoiced decision matters here too. An “s” isn’t a periodic vowel, and a throat model shouldn’t try to invent one. A good processor leaves those consonants largely intact and crossfades between unprocessed noise and corrected vowels.

Conclusion: The Engineering Behind Auto-Tune and Pitch Correction

When you strip away the interface, the Auto-Tune algorithm is solving a surprisingly specific problem: change the pitch of a performance without changing its timing or the qualities that make it sound like that singer. First, estimate the fundamental frequency. Then pick a musical target, move the pitch toward it, and preserve or deliberately reshape the vocal formants.

FFT-based autocorrelation and YIN are one way to measure the note. TD-PSOLA and phase vocoders are two established approaches to the actual pitch shifting, while a source-filter model such as LPC can help handle the formants. Auto-Tune, Melodyne, Waves Tune, and Logic Flex Pitch don’t necessarily share that exact implementation, but they all have to solve those underlying problems.

What makes a good pitch corrector impressive isn’t simply hitting the nearest note. It’s knowing when a sound isn’t a note at all, avoiding octave jumps, keeping vibrato intact, and handling consonants without turning them into metallic artifacts. The difficult part is changing just enough of the signal while leaving the rest alone.

For natural studio correction, you should prefer a slower Retune Speed and a light hand with formants. The singer should still sound like themselves. Push Retune Speed to zero and the same basic process becomes the hard-tuned effect heard across modern music. You haven’t changed the goal of the processor; you’ve changed how quickly it gets there.

The post The Auto-Tune Algorithm: Science and Engineering appeared first on TechOpt.

]]>
https://www.techopt.io/music-production/the-auto-tune-algorithm-science-and-engineering/feed 0
How to Download Images from Google Docs https://www.techopt.io/web/how-to-download-images-from-google-docs https://www.techopt.io/web/how-to-download-images-from-google-docs#respond Sun, 11 Oct 2026 16:30:51 +0000 https://www.techopt.io/?p=1050 Google Docs makes it easy to insert images. However, when you want to pull those images back out, the UI gives you nothing. It seems almost impossible to copy or download images from Google Docs! To start, Docs doesn’t show a “Download image” button. Worse, it also doesn’t give you “Save image as…” when you […]

The post How to Download Images from Google Docs appeared first on TechOpt.

]]>
Google Docs makes it easy to insert images. However, when you want to pull those images back out, the UI gives you nothing. It seems almost impossible to copy or download images from Google Docs!

To start, Docs doesn’t show a “Download image” button. Worse, it also doesn’t give you “Save image as…” when you right-click. As a result, Google Docs effectively doesn’t let you download embedded images directly, even with a right click.

Fortunately, one export option does get the job done: export the doc as a zipped web page.

Why this is annoying

If you’ve tried the obvious moves, then you’ve already hit the same dead end:

  • Right-click an image → no “Save image as…”
  • Select an image → no export action
  • Copy/paste → normally doesn’t work (and quality can drop if it does)

In other words, Docs treats images as part of the document canvas, not as separate files you can retrieve.

The workaround: export the Doc as a zipped web page

Instead of fighting the editor, you can force Google Docs to package the document like a small website. That way, the package includes the images as standalone files.

Steps

  1. First, open your Google Doc.
  2. Next, click File → Download → Web Page (.html, zipped).
    Download google doc as web page from menu
  3. Then, find the downloaded .zip file on your computer.
  4. After that, unzip it:
    • macOS: double-click the zip
    • Windows: right-click → Extract All…
  5. Finally, open the extracted folder.

At this point, you’ll typically see:

  • An .html file (your document content)
  • A companion folder (often named something like <document name>_files)
extracted google docs zip with images folder

Now open the companion folder. Inside, you’ll find the exported images as .png/.jpg/.gif files.

extracted images from google docs zip download

What to expect after you extract the zip

Filenames won’t match your document

Generally, Docs assigns generic names like image1.png, image2.jpg. Therefore, if you export many images, plan to rename them.

Image formats follow the originals (mostly)

In most cases, Docs keeps the original format (JPG stays JPG, PNG stays PNG). Still, some edge cases can trigger re-encoding, especially if you pasted content from elsewhere.

Quality usually holds up

Typically, exports preserve the stored resolution. That said, if you copied an image from a low-res source, the export can’t recover what never existed in the Doc.

Quick troubleshooting for downloading images from Google Docs

You don’t see an images folder

First, confirm you chose Web Page (.html, zipped). Otherwise, if you used PDF or DOCX, you likely won’t get a clean asset folder.

Your device blocks zip downloads or extraction

Sometimes work/school policies restrict downloads. In that case, try a different browser, download to Desktop/Documents, or use a personal machine.

You only need one image

Even so, this method stays the most predictable option. After all, Docs still won’t offer a direct “download this image” action inside the editor.

Why this works

Essentially, the web page export turns your document into an HTML page plus assets. Because HTML needs separate image files to render correctly, Google Docs places each embedded image into an assets folder.

Wrap-up

Ultimately, Google Docs doesn’t provide a direct way to download images from a document, and right-click won’t save you here. Instead, use the export path that forces Docs to create separate files:

File → Download → Web Page (.html, zipped) → unzip → open the *_files folder → grab your images.

The post How to Download Images from Google Docs appeared first on TechOpt.

]]>
https://www.techopt.io/web/how-to-download-images-from-google-docs/feed 0
How to Install Home Assistant on Proxmox Step by Step https://www.techopt.io/smart-home/how-to-install-home-assistant-on-proxmox-step-by-step https://www.techopt.io/smart-home/how-to-install-home-assistant-on-proxmox-step-by-step#respond Sat, 15 Aug 2026 01:44:01 +0000 https://www.techopt.io/?p=1346 I decided to install Home Assistant on Proxmox instead of running it on a dedicated Raspberry Pi or another physical computer. Since I already had a Proxmox server running in my homelab, giving Home Assistant OS its own virtual machine made more sense and let me manage it alongside my other VMs. These are the […]

The post How to Install Home Assistant on Proxmox Step by Step appeared first on TechOpt.

]]>
I decided to install Home Assistant on Proxmox instead of running it on a dedicated Raspberry Pi or another physical computer. Since I already had a Proxmox server running in my homelab, giving Home Assistant OS its own virtual machine made more sense and let me manage it alongside my other VMs.

These are the steps I used to install Home Assistant on Proxmox. I chose to install the full Home Assistant Operating System (HAOS) rather than running Home Assistant in a regular Linux VM or LXC container.

Home Assistant provides an official KVM/Proxmox .qcow2 disk image specifically for this type of installation. The process is slightly different from installing a normal operating system from an ISO because we import this prebuilt disk image into Proxmox instead.

I based part of my process on this community guide rather than using one of the automated helper scripts.

Before Installing Home Assistant on Proxmox

For my Home Assistant VM, I used:

  • 2 CPU cores
  • 4096 MB (4 GB) RAM
  • q35 machine type
  • OVMF (UEFI) BIOS
  • Home Assistant’s KVM/Proxmox QCOW2 image
  • The default Proxmox network interface

Home Assistant’s official documentation currently lists a minimum of 2 vCPUs and 2 GB of RAM for a virtual machine. I decided to give mine 4 GB of RAM instead. You can always increase the resources later if necessary.

You will also need access to the Proxmox web interface and shell (either via web or SSH) for the Proxmox node where you want Home Assistant to run.

Steps to Install Home Assistant on Proxmox

1. Get the Home Assistant KVM/Proxmox Image

First, go to the Home Assistant alternative installation page and find the download for KVM/Proxmox.

KVM/Proxmox download link on Home Assistant alternative downloads page

Home Assistant provides this image in QCOW2 format, which is exactly what we need for Proxmox.

Instead of downloading the image to my computer and uploading it again to Proxmox, I downloaded it directly from the Proxmox shell.

Right-click the KVM/Proxmox download link on the Home Assistant website and copy the link address.

copy link on Home Assistant download page

Then, open the Proxmox web interface, select your Proxmox node and open Shell.

Download the file using wget:

wget <HOME-ASSISTANT-QCOW2-UL>

For example, your command will look similar to:

wget https://github.com/home-assistant/operating-system/releases/download/<version>/haos_ova-<version>.qcow2.xz

downloading Home Assistant qcow2 on Proxmox via web shell

Press Enter after typing the command.

Alternatively, you can SSH into the Proxmox node to run these commands.

I recommend copying the current URL directly from Home Assistant instead of copying an old version number from another guide. That way, you will download the current Home Assistant OS image.

2. Decompress the Home Assistant QCOW2 Image

The downloaded QCOW2 image is compressed using XZ, so we need to decompress it before importing it into Proxmox.

Run:

unxz haos_ova-<version>.qcow2.xz

Replace the filename with the actual filename you downloaded.

For example:

unxz haos_ova-18.2.qcow2.xz

The version above is only an example. Use the filename you actually downloaded.

downloading and unzipping home assistant image for proxmox

After extraction, you should have a file ending in:

.qcow2

If you aren’t sure which directory you downloaded the file into, run:

pwd

You can also list the files in the current directory with:

ls

If you opened the shell through the Proxmox web interface, you will commonly be working from /root.

Show current directory when installing home assistant on proxmox with pwd and ls commands

The Proxmox forum guide uses the same wget and unxz process to obtain and extract the Home Assistant image.

3. Create a New Home Assistant VM in Proxmox

Next, go back to the Proxmox web interface and click Create VM.

We are going to create the VM without an installation ISO because the Home Assistant QCOW2 file will become the VM’s boot disk.

General

Give the VM a name such as:

HomeAssistant

Take note of the VM ID. We will need this number when importing the Home Assistant disk later. In my case, this was 103.

In Advanced settings I also enabled:

Start at boot

This way, Home Assistant will automatically start when my Proxmox server starts.

general tab settings creating vm for proxmox

OS

Under the OS tab, select:

Do not use any media

We don’t need an ISO because Home Assistant is already installed inside the QCOW2 image.

os tab settings creating vm for proxmox

System

This part is important.

For Machine, select:

q35

For BIOS, select:

OVMF (UEFI)

Select a storage location for the EFI disk. In many installations this will be:

local-lvm

In my case it was actually a storage location called VMs.

I also unchecked:

Pre-Enroll keys

Home Assistant requires UEFI when running as a virtual machine, and the referenced Proxmox configuration uses q35 with OVMF and Secure Boot keys disabled.

system tab settings creating vm for proxmox

Disks

Proxmox normally creates an empty disk when you create a VM.

We don’t need it.

Delete the automatically created SCSI disk from the VM configuration. The Home Assistant QCOW2 image that we downloaded earlier will become our disk instead.

disks tab settings creating vm for proxmox

CPU

I assigned:

2 cores

cpu tab settings creating vm for proxmox

You can give Home Assistant more CPU resources later if your installation grows.

Memory

I assigned:

4096 MB

That gives the VM 4 GB of RAM.

Although Home Assistant currently specifies 2 GB as the minimum for a VM, I preferred giving it 4 GB from the beginning.

memory tab settings creating vm for proxmox

Network

I left the network configuration at the Proxmox defaults.

For a typical installation, the VM should be connected to your normal Proxmox bridge so Home Assistant appears as another device on your LAN.

network tab settings creating vm for proxmox

If you’re using VLANs or a more complicated network configuration, adjust this accordingly.

Finish creating the VM.

Do not start it yet.

finish tab settings creating vm for proxmox

4. Import the Home Assistant QCOW2 Disk into Proxmox

Now we need to import the Home Assistant disk into the VM we just created.

Go back to the Proxmox node’s Shell.

The general syntax for importing a QCOW2 image is:

qm importdisk <VM-ID> <QCOW2-FILE> <STORAGE>

For example, if:

  • Your Home Assistant VM ID is 103
  • Your Home Assistant QCOW2 file is in /root
  • Your VM storage is local-lvm

You would run something similar to:

qm importdisk 103 /root/haos_ova-<version>.qcow2 local-lvm

Make sure you replace the VM ID, filename and storage with the values from your own Proxmox installation.

qm importdisk with haos qcow2 to storage

Let the import finish before continuing.

5. Attach the Imported Home Assistant Disk

Once the import completes, return to the Proxmox web interface.

Select your Home Assistant VM and open:

Hardware

You should now see something similar to:

Unused Disk 0

This is the Home Assistant disk we just imported.

Select the unused disk and click Edit.

set discard bit home assistant disk proxmox

If your Proxmox storage backing this VM is on an SSD, you should enable Discard.

Then, click Add.

set discard bit home assistant disk proxmox

The disk should now be attached to the Home Assistant VM, commonly as something similar to:

scsi0

showing attached drive proxmox home assistant vm

6. Set the Home Assistant Disk as the Boot Disk

Before starting the VM, we need to make sure Proxmox actually boots from the imported Home Assistant disk.

Select the VM and go to:

Options > Boot Order

Click Edit.

Enable the imported Home Assistant disk. In my case, this was the scsi0 disk.

Disable any unnecessary boot devices so the Home Assistant disk is the VM’s primary boot device.

check home assistant drive and uncheck unnecessary boot devices proxmox

7. Start the Home Assistant VM

We can finally start Home Assistant.

Click Start.

Then, open the VM’s Console.

Home Assistant OS should begin booting!

If everything is configured correctly, Home Assistant will eventually display network information in the console, including the address you can use to access the web interface.

home assistant running in proxmox

8. Open the Home Assistant Web Interface

Once Home Assistant has booted, open a web browser from another computer on your network.

Home Assistant may be available at:

http://homeassistant.local:8123

Alternatively, you can use the IP address shown in the Home Assistant console:

http://<HOME-ASSISTANT-IP>:8123

For example:

http://192.168.1.100:8123

Home Assistant’s documentation recommends using the IP address directly if hostname discovery doesn’t work on your network.

You should now see the Home Assistant onboarding page.

home assistant onboarding page

From here, you can create your Home Assistant account and continue with the normal initial setup.

That’s it! Home Assistant OS is now running as a virtual machine in Proxmox.

Troubleshooting Home Assistant on Proxmox

Home Assistant VM Says There Is No Bootable Disk

First, go to:

VM > Options > Boot Order

Make sure the imported Home Assistant disk is enabled.

It will commonly appear as something such as:

scsi0

The imported QCOW2 disk needs to be selected as a bootable device.

Also confirm that you actually attached the Unused Disk after running qm importdisk.

VM Fails to Boot or Shows a UEFI/Secure Boot Error

Check the VM’s system configuration.

I used:

  • Machine: q35
  • BIOS: OVMF (UEFI)
  • Pre-Enroll Keys: Disabled

Home Assistant requires UEFI for the virtual machine, while the Proxmox forum procedure specifically disables the pre-enrolled Secure Boot keys.

There are also reports in the referenced forum thread of Secure Boot preventing the Home Assistant image from booting until it was disabled.

qm importdisk Says the QCOW2 File Does Not Exist

Check your current directory:

pwd

Then list your files:

ls

You can also specify the complete path to the file:

qm importdisk 103 /root/haos_ova-<version>.qcow2 local-lvm

Also double-check the filename. The extension should be:

.qcow2

Make sure you have already decompressed the .qcow2.xz file with unxz.

homeassistant.local:8123 Does Not Work

Try accessing Home Assistant by IP address instead:

http://<HOME-ASSISTANT-IP>:8123

The Home Assistant documentation specifically recommends using the VM’s IP address when local hostname resolution does not work.

You can find the assigned address from the Home Assistant VM console or from your router/DHCP server.

What About Zigbee, Z-Wave and Other USB Devices?

If you use Home Assistant with a Zigbee, Z-Wave or other USB adapter, the physical USB device will need to be made available to the Home Assistant VM.

Home Assistant’s virtualization documentation specifically accounts for passing USB hardware such as Zigbee and Z-Wave controllers through to a VM.

I would get the basic Home Assistant VM installed and working first before configuring any USB passthrough. This makes it much easier to troubleshoot because you know the base Home Assistant installation is working before adding additional hardware.

If you’re planning to use a Zigbee coordinator with Home Assistant, you’ll also need to decide whether to use ZHA or Zigbee2MQTT. I’ve compared both options separately, along with the best Zigbee channels for Home Assistant if you’re trying to avoid Wi-Fi interference.

Why I Installed Home Assistant Manually

There are community scripts available that can automate much of the process of installing Home Assistant on Proxmox.

However, I wanted to install it manually.

Doing it this way makes the VM configuration much more obvious. You know exactly which machine type, BIOS, CPU, memory, storage and boot disk the Home Assistant VM is using.

It also makes troubleshooting easier later because the installation isn’t hidden behind a script.

The process really isn’t complicated once you understand that the Home Assistant download is a preinstalled QCOW2 disk rather than a conventional installation ISO.

The basic process is simply:

  1. Download the Home Assistant QCOW2 image.
  2. Decompress it.
  3. Create an empty Proxmox VM.
  4. Import the QCOW2 image using qm importdisk.
  5. Attach the imported disk.
  6. Make it bootable.
  7. Start the VM.
  8. Open Home Assistant on port 8123 at http://homeassistant.local:8123.

Conclusion

Installing Home Assistant on Proxmox is a little different from creating a typical Linux VM because there isn’t an installer ISO involved. Instead, Home Assistant provides a ready-to-use QCOW2 image that we import directly into the virtual machine.

These are the steps I used to install Home Assistant on Proxmox, and once the VM configuration and disk import were complete, Home Assistant OS booted like any other virtual machine.

For my setup, 2 CPU cores, 4 GB of RAM, q35 and OVMF worked well as a straightforward starting configuration.

Running Home Assistant this way also keeps it nicely contained in its own VM while letting Proxmox handle the underlying virtual hardware and startup of the system.

Remarks

  • Home Assistant provides an official KVM/Proxmox QCOW2 image, so make sure you download that image to install Home Assistant on Proxmox rather than one intended for VirtualBox or VMware.
  • I used 2 CPU cores and 4 GB of RAM. Home Assistant currently lists 2 vCPUs and 2 GB of RAM as the minimum VM requirements.
  • Make sure the VM uses OVMF/UEFI. Home Assistant requires UEFI to boot as a virtual machine.
  • If the VM refuses to boot, double-check that Pre-Enroll Keys/Secure Boot is disabled and that the imported Home Assistant disk is selected in the boot order.
  • If homeassistant.local doesn’t resolve on your network, access Home Assistant directly using its IP address and port 8123, such as http://192.168.1.100:8123.

The post How to Install Home Assistant on Proxmox Step by Step appeared first on TechOpt.

]]>
https://www.techopt.io/smart-home/how-to-install-home-assistant-on-proxmox-step-by-step/feed 0
WAV vs FLAC vs ALAC: Best Format for Media Storage https://www.techopt.io/music-production/wav-vs-flac-vs-alac-best-format-for-media-storage https://www.techopt.io/music-production/wav-vs-flac-vs-alac-best-format-for-media-storage#respond Sat, 18 Jul 2026 02:42:07 +0000 https://www.techopt.io/?p=1298 If you are building a serious music library, ripping CDs, archiving old recordings, or organizing audio for a media server, you have probably run into three common formats: WAV, FLAC and ALAC. At first, the choice can feel more complicated than it really is. WAV is often seen as the “studio quality” option, FLAC is […]

The post WAV vs FLAC vs ALAC: Best Format for Media Storage appeared first on TechOpt.

]]>
If you are building a serious music library, ripping CDs, archiving old recordings, or organizing audio for a media server, you have probably run into three common formats: WAV, FLAC and ALAC.

At first, the choice can feel more complicated than it really is. WAV is often seen as the “studio quality” option, FLAC is popular with audiophiles and media server users, and ALAC is commonly associated with Apple devices.

The good news is that all three can store lossless audio. However, they are not equally convenient for long-term media storage.

In this blog, I will compare WAV, FLAC and ALAC from a practical storage perspective, including file size, metadata, compatibility, editing, and which format makes the most sense for different types of music libraries.

WAV vs FLAC vs ALAC: Quick Answer

For most people, FLAC is the best format for long-term media storage.

It gives you the same audio quality as WAV, usually uses much less space, supports metadata well, and works nicely with media servers like Plex, Jellyfin, Kodi, and many dedicated music players.

WAV still has its place, especially for recording, editing, sample libraries, and professional audio workflows, but it is usually not the most efficient format for storing a large music collection.

ALAC is also a great choice if you mainly live in the Apple ecosystem.

What Is WAV?

WAV, short for Waveform Audio File Format, is an audio container format originally associated with IBM and Microsoft. It is commonly used to store uncompressed PCM audio, although WAV can technically contain compressed audio too.

In simple terms, a typical WAV file stores raw audio data without trying to make the file smaller.

That makes WAV simple, widely supported, and excellent for editing. However, it also means the files can get very large.

For example, CD-quality audio at 16-bit / 44.1 kHz uses roughly 10 MB per minute in uncompressed stereo WAV format. A full album can easily take hundreds of megabytes.

WAV Pros

WAV is excellent when you want maximum compatibility with audio editors, DAWs, samplers, and professional tools. It is also simple to process because the audio is usually stored in an uncompressed format.

This makes WAV a great format for:

  • Recording projects
  • Audio editing
  • Sample packs
  • Temporary production files
  • Exporting masters before final encoding

WAV Cons

The biggest problem with WAV is storage efficiency. Since typical WAV files are uncompressed, they take up much more space than FLAC or ALAC.

WAV can also be less pleasant for music library organization. Metadata support exists, but in practice, tagging WAV files is not always as consistent across music players compared to FLAC or ALAC.

If you are storing thousands of songs, this matters. Album art, artist names, track numbers, genres, and release dates are all important when browsing a media library.

What Is FLAC?

FLAC stands for Free Lossless Audio Codec. It compresses audio without losing quality, similar to how ZIP can compress files without changing their contents. Xiph.Org describes FLAC as lossless audio compression designed specifically for audio.

That means a FLAC file can be decoded back into the same audio data you would get from the original WAV source.

In other words, FLAC is not like MP3. MP3 throws away audio data to save space, and FLAC keeps the audio intact while still reducing file size.

FLAC Pros

FLAC is probably the best all-around format for storing a personal lossless music library.

It usually saves a lot of space compared to WAV, supports strong metadata tagging, is open, and is widely supported across many platforms and media players.

FLAC is especially useful for:

  • CD rips
  • Lossless music libraries
  • Plex, Jellyfin, Kodi, and other media servers
  • Archiving music without wasting space
  • Keeping album art and metadata organized

FLAC files are also easy to verify. Since FLAC supports checksums, it is a very good format for people who care about long-term archival integrity.

FLAC Cons

The main downside is Apple compatibility. FLAC support is much better than it used to be, but ALAC still feels more native if you use Apple Music, iPhones, iPads, and macOS as your main music ecosystem.

FLAC is also compressed, so it takes a small amount of CPU power to decode. However, on any modern computer, phone, or media server, this is usually not a concern at all.

What Is ALAC?

ALAC stands for Apple Lossless Audio Codec. It is Apple’s lossless compression format. Apple says ALAC preserves the original audio data while reducing file size, and Apple Music uses ALAC for its lossless catalog.

ALAC is similar to FLAC in the most important way: it is lossless.

That means ALAC and FLAC can both store the same quality of audio. The main difference is ecosystem support.

ALAC Pros

ALAC is a great option if your music life revolves around Apple devices.

It works well with:

  • Apple Music
  • iPhone
  • iPad
  • macOS
  • Apple TV
  • AirPlay-focused setups

ALAC files are usually stored in .m4a containers, which also have good metadata support. If you want lossless files that feel native in Apple’s ecosystem, ALAC is often the easiest choice.

ALAC Cons

Outside of Apple-focused setups, ALAC is not usually as popular as FLAC.

Many apps and media servers can play ALAC just fine, but FLAC tends to be the more common standard among audiophiles, archivists, home server users, and open-source media tools.

If you are building a media library that you want to keep flexible across many systems, FLAC is usually the safer long-term bet.

WAV vs FLAC vs ALAC File Size

File size is one of the biggest reasons to choose FLAC or ALAC over WAV.

A WAV file usually stores audio without compression. FLAC and ALAC compress the same audio data losslessly, so they can reduce storage use while keeping the same quality.

A rough comparison for CD-quality music:

FormatCompressionTypical SizeAudio Quality
WAVNoneLargestLossless
FLACLosslessSlightly smaller than WAVLossless
ALACLosslessSimilar to FLACLossless

The exact savings depend on the music. Simple acoustic music may compress better than dense electronic or metal tracks. Still, FLAC and ALAC are usually far more storage-friendly than WAV.

For a small collection, WAV may not seem like a big deal. For thousands of albums, the difference can become massive.

Does FLAC or ALAC Sound Worse Than WAV?

No. FLAC and ALAC do not sound worse than WAV when they are created properly from the same source.

They are lossless formats. When decoded, they reproduce the original audio data.

The difference is not sound quality. The difference is storage, tagging, compatibility, and workflow.

If you convert a WAV file to FLAC and then decode that FLAC back to WAV, the audio data should match. The FLAC file is simply a more efficient way of storing it.

However, this only applies if the source is truly lossless. Converting an MP3 to FLAC does not restore lost quality. It just creates a larger file containing already-damaged audio.

I covered that problem in more detail in my guide on how to identify fake FLAC files. If you’d rather check a file in the browser, use the fake FLAC checker.

Metadata and Library Organization

Metadata is where FLAC and ALAC really shine for media storage.

When you are managing a large music library, you usually want:

  • Artist
  • Album
  • Track title
  • Track number
  • Genre
  • Year
  • Album art
  • Disc number
  • Composer
  • ReplayGain or loudness tags

FLAC handles this very well. ALAC also handles metadata well, especially in Apple software.

WAV can store metadata, but support is not as consistent across players and tagging tools. This makes WAV less ideal for a neatly organized personal music library.

For media storage, metadata matters almost as much as audio quality. A perfectly preserved WAV collection is annoying if half your album art, track numbers, or artist tags do not show correctly.

Compatibility: Which Format Plays Everywhere?

WAV has the broadest basic compatibility. Almost anything can open a WAV file.

FLAC is extremely well supported across modern media players, servers, and audio tools. It is especially common in open-source and home media server setups.

ALAC is strongest inside the Apple ecosystem. It is also supported by many modern players, but it is not usually the default choice for non-Apple media libraries.

Here is the practical breakdown:

Use CaseBest Format
Professional recording and editingWAV
Long-term music library storageFLAC
Apple-focused lossless libraryALAC
Plex or Jellyfin music serverFLAC
CD ripping archiveFLAC
Sharing with a studio or DAWWAV
iPhone-first local music libraryALAC

When Should You Use WAV?

Use WAV when you are actively working with audio.

For example, WAV makes sense when recording vocals, editing podcasts, exporting stems, creating samples, or moving files between DAWs.

It is simple, uncompressed, and widely accepted by professional tools.

However, once the project is done, you may want to store the final version as FLAC or ALAC to save space while keeping the audio lossless.

Think of WAV as a production format, not always the best library format.

When Should You Use FLAC?

Use FLAC when you want the best general-purpose format for storing lossless music.

This is what I would choose for a personal archive, a home server, or a large music collection that needs to remain flexible over time. FLAC is what I use for my media server.

FLAC is especially good if you care about open formats, metadata, file integrity, and compatibility with media server software.

For most TechOpt readers who are building a home media setup, FLAC is probably the best default choice.

When Should You Use ALAC?

Use ALAC if you are heavily invested in Apple devices and want lossless audio that fits nicely into that ecosystem.

If your main playback devices are an iPhone, iPad, Mac, Apple TV, or Apple Music app, ALAC can be more convenient than FLAC.

It is also a good choice if you want to sync local lossless files through Apple-friendly workflows.

However, if you are trying to build a more platform-neutral archive, I would still lean toward FLAC.

Should You Convert WAV to FLAC?

Yes, in many cases.

If you have a large WAV music collection that you are using for listening and storage rather than active editing, converting it to FLAC can save a lot of disk space without reducing quality.

Just make sure you keep a backup before doing any large batch conversion.

A common workflow is:

  1. Keep active recording projects in WAV.
  2. Export finished masters as WAV.
  3. Convert final listening copies to FLAC.
  4. Store the FLAC files in your main media library.
  5. Keep original project files separately if needed.

This gives you the best of both worlds: production flexibility and efficient storage.

Should You Convert FLAC to ALAC?

Only if you need better Apple compatibility.

Converting FLAC to ALAC should preserve audio quality because both formats are lossless. However, you should still be careful with metadata during conversion.

Some tags may not transfer exactly depending on the software you use.

If your FLAC library already works with your devices, there is no urgent reason to convert it. But if you want everything to feel native in Apple Music or on iOS, ALAC may be worth it.

Should You Convert MP3 to FLAC or ALAC?

No, not for quality reasons.

Converting MP3 to FLAC or ALAC will not restore the audio data that was removed during MP3 compression. It will only create a larger lossless file that contains lossy audio.

This is one of the reasons fake FLAC files exist. Someone can take a lossy MP3, convert it to FLAC, and make it look like a high-quality file. But the missing audio information is still gone.

If you care about lossless quality, start from a true lossless source such as a CD rip, studio master, or legitimate lossless download.

Best Format for Media Servers

For media servers, I would usually choose FLAC.

It is efficient, open, reliable, and well supported by most serious media software. It also keeps your library easy to move between systems in the future.

If you are using Plex, Jellyfin, Kodi, Navidrome, or another self-hosted music setup, FLAC is a very practical choice.

WAV will work, but it wastes space.

ALAC may also work, but unless you specifically need Apple compatibility, FLAC is usually the more natural fit for a server-based library.

Final Recommendation

For most people, the best format for media storage is FLAC.

It gives you lossless quality, smaller files than WAV, strong metadata support, and excellent compatibility across modern media players and servers.

Choose WAV when you are recording, editing, exporting stems, or working in a professional audio environment.

Choose ALAC when you want a lossless library that works smoothly with Apple devices and Apple Music.

The simple rule is:

Use WAV for production, FLAC for archiving, and ALAC for Apple-focused playback.

That keeps your audio quality intact while making your library easier to store, manage, and enjoy.

The post WAV vs FLAC vs ALAC: Best Format for Media Storage appeared first on TechOpt.

]]>
https://www.techopt.io/music-production/wav-vs-flac-vs-alac-best-format-for-media-storage/feed 0
Raspberry Pi Model B Original (2012) Uses in 2026 https://www.techopt.io/hardware/raspberry-pi-model-b-original-2012-uses https://www.techopt.io/hardware/raspberry-pi-model-b-original-2012-uses#respond Tue, 13 Jan 2026 23:49:24 +0000 http://localhost:8080/?p=53 It’s hard to believe that the original Raspberry Pi 1 Model B was released 14 years ago in 2012! With a 700 MHz ARM processor, 512 MB of RAM, 2x USB 2.0 ports and 10/100 Ethernet, its hardware is nothing impressive by today’s standards. However, if you’ve got one (or many!) of these kicking around, […]

The post Raspberry Pi Model B Original (2012) Uses in 2026 appeared first on TechOpt.

]]>
It’s hard to believe that the original Raspberry Pi 1 Model B was released 14 years ago in 2012! With a 700 MHz ARM processor, 512 MB of RAM, 2x USB 2.0 ports and 10/100 Ethernet, its hardware is nothing impressive by today’s standards. However, if you’ve got one (or many!) of these kicking around, there are still some viable applications to put it to good use.

The projects in this article are ones that the original Model B actually has adequate power to run without sacrificing usability or performance, not just “will run, but not well” projects.

Similarly, a lot of these should work with the Model A. However, keep in mind that the Model A only has 256 MB of RAM, which limits it further.

1. Raspberry Pi Print Server

Make an old USB printer WiFi and AirPrint compatible using an old Raspberry Pi with Raspbian. By connecting the printer to a USB port on the Pi and installing CUPS, you can share your USB printer with your network to make it wireless.

Additionally, CUPS also now supports broadcasting as AirPrint devices. Once the printer is setup in CUPS, you should be able to print to it from your Apple devices as well.

2. Pi-Based Digital Picture Frame

A digital picture frame is probably one of the lowest resource projects you can do. Therefore, this makes it perfect for the original Raspberry Pi. You’ll simply need an old screen with an HDMI input. You can even use a screen with a composite input, since the original Pi has a composite output!

Choose an OS, put your photos on your SD card or a USB key and install some image slideshow software. Some people even get creative with decorative framing around the screen.

User ShanJones01’s implementation of a Raspberry Pi digital picture frame over on Instructables (Image source)

3. Raspberry Pi Web Server

You can run a lightweight web server such as nginx or lighttpd on your older Raspberry Pi to serve static web pages and basic websites. You can also try Apache, but keep in mind that Apache is not as lightweight as nginx or lighttpd, so your performance probably won’t be as good.

The original Pi Model B definitely isn’t powerful enough to serve a website to hundreds of users, however, for a few users it should be more than adequate.

4. Self-Host Bitwarden

This is one of my personal favourites. Bitwarden is an opensource password manager that you can self-host. It has accompanying desktop apps, mobile apps, and browser extensions.

The original Pi may not be powerful enough to host full Bitwarden, but it will easily run Vaultwarden. Vaultwarden is an alternative implementation of the Bitwarden API written in Rust, which makes it super fast and less resource-intensive than full Bitwarden. You can still use it with the official Bitwarden apps and extensions.

Simply install docker and spin up the Vaultwarden container. Again, it might not work great for hundreds of users, but our Pi 1 Vaultwarden instance is working great for our family of 6!

5. Internet Radio, Bluetooth or AirPlay Receiver

This one is also a personal favourite to modernize an old stereo system. All you need is a stereo system or set of speakers with an AUX port. This way you can connect the headphone jack of the Raspberry Pi right into the stereo system. Alternatively, if the stereo is older and has an RCA input, you can use a 3.5 mm to RCA adapter.

Install an OS and run your favourite music apps to play directly to your speakers. Additionally, you can setup Bluetooth pairing to use it as a Bluetooth speaker. You can also install shairport-sync to support AirPlay from Apple devices.

Conclusion

The Pi has come a long way since it was first introduced. Even though at first glance the original Raspberry Pi 1 Model B looks severely under-powered by today’s standards, it still has some great uses for applications where a lot of processing power isn’t needed.

The post Raspberry Pi Model B Original (2012) Uses in 2026 appeared first on TechOpt.

]]>
https://www.techopt.io/hardware/raspberry-pi-model-b-original-2012-uses/feed 0
Install and Run AppImage Software on Linux (Step-by-Step) https://www.techopt.io/linux/install-and-run-appimage-software-on-linux-step-by-step https://www.techopt.io/linux/install-and-run-appimage-software-on-linux-step-by-step#respond Sun, 28 Dec 2025 01:27:37 +0000 https://www.techopt.io/?p=1197 AppImage is one of the easiest ways to run Linux apps because it’s typically a single, self-contained file rather than a traditional install package. In this guide, you’ll learn how to run AppImage files on Linux safely and cleanly: how to organize them, make them executable, launch them, and optionally add a shortcut with icon […]

The post Install and Run AppImage Software on Linux (Step-by-Step) appeared first on TechOpt.

]]>
AppImage is one of the easiest ways to run Linux apps because it’s typically a single, self-contained file rather than a traditional install package.

In this guide, you’ll learn how to run AppImage files on Linux safely and cleanly: how to organize them, make them executable, launch them, and optionally add a shortcut with icon so the app shows up in your applications menu.

You can follow this guide regardless of the distribution or desktop environment you are using!

What you need

  • A downloaded .AppImage file (from the app’s official site)
  • A file manager (Dolphin, Files/Nautilus, etc.) and/or a terminal

Step 1: Put your AppImage somewhere organized

Yes, you can run an AppImage straight from your Downloads folder. But if you download a few of these over time, they get messy fast.

A simple structure I like is:

  • ~/bin/ for AppImages (and other portable apps)
  • One folder per app inside ~/bin/ (helps keep icons, config files, and updates tidy)

Example:

mkdir -p ~/bin/<app-name>

Then move your AppImage into that folder using your file manager (drag and drop) or the terminal:

mv ~/Downloads/<app-name>.AppImage ~/bin/<app-name>/

Why one folder per app? Some portable apps want read/write access to their own folder (for example, to download an update). Keeping each AppImage in its own folder avoids weird permission issues and keeps everything clean.

What about multi-user systems?

If multiple users need the same AppImage, putting it in one users home folder might not be ideal. In that case, storing it under /opt/<app-name>/ is common, but you must set permissions properly so users can run (and potentially update) it.


Step 2: Make the AppImage executable (required)

Most downloads are not executable by default (this is normal on Linux). To run an AppImage, you must mark it as executable first.

⚠ This is the critical step. AppImage software will not run without doing this step.

Option A: Do it in your file manager (GUI)

  • Right-click the AppImage
  • Open Properties
  • Go to Permissions
  • Enable: Allow executing file as program (or your file manager’s equivalent)
Mark as executable to run AppImage in file explorer

Option B: Do it in the terminal (works everywhere)

Change into the folder where the AppImage lives, then run chmod:

cd ~/bin/<app-name>

chmod +x <app-name>.AppImage

If you want to see that execute bit as octal, use the chmod calculator.


Step 3: Run the AppImage

Now you can run your AppImage file in either of these ways:

  • Double-click the file in your file manager, or
  • Run it from the terminal:

./<app-name>.AppImage


Step 4 (optional): Add the AppImage application to your application menu

These steps will vary a bit depending on your desktop environment, but you should be able to find equivalent settings.

If you’re on KDE Plasma, you can follow these instructions:

  1. Right-click your application launcher (start menu)
  2. Click Edit Applications…
  3. Choose a category (like Utilities)
  4. Click New Item
  5. Set the Program to the full path of your AppImage
  6. Pick an icon (optional but recommended)
  7. Save
Add a shortcut to our AppImage in software menu

Tip: Download a PNG icon (transparent background looks best) and store it in the same folder as your AppImage so everything stays together.


Step 5 (optional): Use AppImageLauncher to automate menu integration

If you prefer a more automatic approach, AppImageLauncher can integrate AppImages into your menu, move them into a central location, and even provide update/remove entry functionality through your launcher.

It’s not supported on every distro, but if it works on yours, it can save time.


Troubleshooting tips

Nothing happens when you try to run AppImage

Run it from a terminal to see error output:

cd ~/bin/<app-name>

./<app-name>.AppImage

Want to inspect whats inside an AppImage?

You can mount AppImages read-only using:

./<app-name>.AppImage --appimage-mount


Remarks

  • AppImages are not installed like traditional packages on Linux: you manage them by keeping the file, updating it (if the app supports it), and deleting it when done.
  • A clean folder layout makes it easier to back up, move, or remove apps later.
  • If you want the most “native” feel, menu integration is the final piece.
  • For those less familiar with Linux, ~ is a shorthand placeholder for /home/<user>.

FAQ

Do I have to install anything to run AppImage?

No. You usually just download it, mark it executable, and run it.

Why is my AppImage not executable after downloading?

Because Linux downloads typically remove the executable bit for safety. Therefore, you have to add it back with the GUI permission checkbox or chmod +x.

How do I uninstall an AppImage?

Simply delete the AppImage file (and any shortcuts you created).

The post Install and Run AppImage Software on Linux (Step-by-Step) appeared first on TechOpt.

]]>
https://www.techopt.io/linux/install-and-run-appimage-software-on-linux-step-by-step/feed 0
Upgrade openSUSE Leap to 16.0 from 15.6 https://www.techopt.io/linux/upgrade-opensuse-leap-to-16-0-from-15-6 https://www.techopt.io/linux/upgrade-opensuse-leap-to-16-0-from-15-6#respond Sun, 19 Oct 2025 17:33:07 +0000 https://www.techopt.io/?p=1140 Upgrading openSUSE Leap has evolved! If you’ve tried the old method using the --releasever flag that I talked about in my 15.5 to 15.6 upgrade guide, you’ve probably run into problems. In this updated guide, I’ll cover the new, official and recommended method to upgrade openSUSE Leap to 16.0 from 15.6 using the openSUSE Migration […]

The post Upgrade openSUSE Leap to 16.0 from 15.6 appeared first on TechOpt.

]]>
Upgrading openSUSE Leap has evolved! If you’ve tried the old method using the --releasever flag that I talked about in my 15.5 to 15.6 upgrade guide, you’ve probably run into problems. In this updated guide, I’ll cover the new, official and recommended method to upgrade openSUSE Leap to 16.0 from 15.6 using the openSUSE Migration Tool.

Why the Old --releasever Method No Longer Works

In my previous guide, I showed how you could upgrade openSUSE Leap releases with:

sudo zypper --releasever=16.0 dup

That used to work reliably in earlier Leap versions. However, with SLE (SUSE Linux Enterprise) 16, SUSE introduced major backend and repository format changes. The new openSUSE Leap 16.0 release merges more closely with SLE infrastructure, which means the repositories and release metadata formats have changed significantly.

If you try to use the --releasever flag now, you’ll likely see repository or GPG key errors during the upgrade. That’s because the old repository layout no longer matches Leap 16’s new structure.

The New Official Method: opensuse-migration-tool

Instead of manually changing repositories, Leap 16 introduces a dedicated migration utility designed to handle all the details for you. The tool automatically adjusts your repositories, resolves new dependencies, and manages system configuration changes.

Step 1: Install the Migration Tool

First, fully update your Leap 15.6 system:

sudo zypper refresh
sudo zypper up

Then install the new migration package:

sudo zypper install opensuse-migration-tool

Step 2: Run the Migration Process

Start the migration utility:

sudo opensuse-migration-tool

The tool will analyze your current system, identify obsolete packages, and suggest repository transitions for Leap 16.0. The system prompts you to confirm before proceeding with the distribution upgrade.

Upgrade openSUSE with opensuse-migration-tool

You’ll want to select openSUSE Leap 16.0 with the arrow keys on your keyboard, select OK and hit Enter.

You will probably encounter the following screen about disabling third-party repositories:

Repositories not recognized opensuse-migration-tool

This happens because Leap 16.0 changes how repositories are structured. You can simply hit Enter to confirm.

The upgrade process will then start! Wait a few minutes, then reboot into Leap 16.0 once the process finishes.

opensuse-migration-tool run complete

Step 3: Reboot into Leap 16.0

After the migration completes, simply reboot:

sudo reboot

You’ll now be running openSUSE Leap 16.0 with the updated repository structure.

Troubleshooting Tips

  • Do not use zypper dup --releasever=16.0. It may break dependencies.
  • If you encounter repository signature errors, remove or rename old .repo files in /etc/zypp/repos.d/ before re-running the migration tool.
  • Ensure your disk has sufficient space and that all third-party repositories are disabled before starting the upgrade.

Final Thoughts

The openSUSE team has streamlined the upgrade path to make system migrations more reliable and aligned with SUSE’s enterprise ecosystem. While older zypper --releasever methods are now deprecated, the openSUSE Migration Tool simplifies the process and ensures compatibility with the new Leap 16 architecture.

The post Upgrade openSUSE Leap to 16.0 from 15.6 appeared first on TechOpt.

]]>
https://www.techopt.io/linux/upgrade-opensuse-leap-to-16-0-from-15-6/feed 0
How to Make Ethernet Cables: A Complete Step-by-Step Guide https://www.techopt.io/servers-networking/how-to-make-ethernet-cables-a-complete-step-by-step-guide https://www.techopt.io/servers-networking/how-to-make-ethernet-cables-a-complete-step-by-step-guide#respond Sun, 21 Sep 2025 18:39:42 +0000 https://www.techopt.io/?p=1098 Learning how to make ethernet cables yourself is a cost-effective and customizable way to build a network setup that fits your exact needs. Buying premade cables limits you to fixed lengths and can quickly get expensive, especially if you need several cables of different sizes. By crimping your own cables, you can create perfect lengths […]

The post How to Make Ethernet Cables: A Complete Step-by-Step Guide appeared first on TechOpt.

]]>
Learning how to make ethernet cables yourself is a cost-effective and customizable way to build a network setup that fits your exact needs. Buying premade cables limits you to fixed lengths and can quickly get expensive, especially if you need several cables of different sizes. By crimping your own cables, you can create perfect lengths for your home or office, improve cable management, and even ensure higher quality by using better materials.

This comprehensive guide will walk you through everything you need to know, from selecting the right cable and connectors, to crimping, testing, and troubleshooting your custom cables.


Why Make Your Own Ethernet Cable?

There are several advantages to building your own network cables:

  • Custom Lengths: No more coiled-up mess or cables that come up just short. Instead, you can make cables the exact length you need.
  • Cost Savings: Bulk ethernet cable and connectors are far cheaper per foot than buying pre-made cables.
  • Better Quality Control: You choose the cable type, shielding, and connectors, therefore avoiding cheap copper-clad aluminum (CCA) cables.
  • Skill Building: This is a useful DIY skill for anyone interested in networking, home labs, or IT work.

Tools and Materials Needed

Here’s what you’ll need to make DIY ethernet cables successfully:

  • Ethernet Cable (Cat6, Cat6a, or Cat5e): Prefer solid copper rather than CCA for best performance and compliance with standards. Cat6 bulk cable on Amazon
  • RJ45 Connectors: Choose connectors rated for your cable type (Cat6, Cat6a, or Cat5e). Passthrough connectors are easier for beginners. Cat6 RJ45 passthrough connectors
  • RJ45 Crimping Tool: Used to secure connectors to the cable. Most crimpers also include a wire cutter and stripper. RJ45 crimp tool
  • Cable Tester (Recommended, but optional): Ensures your wiring is correct and detects any faults. Basic cable tester or advanced network tester
  • Strain Relief Boots (Recommended, but optional): Add durability to the connector ends. Strain relief boots
  • Wire Cutters/Scissors: For trimming cable and internal wires. Wire strippers/cutters

Tip: Avoid “Cat7” or “Cat8” cables sold cheaply online. These are not officially recognized Ethernet standards and often use questionable materials.


Step 1: Measure and Cut Your Cable

Pull the amount of cable you need from the box, then add roughly 30 cm (about 1 foot) of extra length for trimming and flexibility. Cut the cable cleanly using the crimper’s cutting blade or a pair of wire cutters.

cut the ethernet cable

Step 2: Strip the Outer Jacket

Use the stripping blade on your crimping tool (or a dedicated wire stripper) to remove 5–10 cm (2–3 inches) of the outer jacket from both ends of the cable. Be careful not to nick the internal wires.

strip outer insulation of ethernet cable

After that, remove the internal string, if present.

cut the string in the cable

At this stage, slide on the strain relief boots if you’re using them—forgetting them is a common mistake. Therefore, it’s best to add them now. You want the larger side facing outward from the end of the cable on both sides.

add strain relief boots to cable

Step 3: Untwist and Arrange the Wires

Inside the jacket are four twisted pairs of wires (8 total). Untwist the pairs and straighten them.

Then, arrange them in either T-568A or T-568B wiring order. Use the same standard on both ends.

T-568A Wiring Order:

  1. White/Green
  2. Green
  3. White/Orange
  4. Blue
  5. White/Blue
  6. Orange
  7. White/Brown
  8. Brown

T-568B Wiring Order (Most Common in North America):

  1. White/Orange
  2. Orange
  3. White/Green
  4. Blue
  5. White/Blue
  6. Green
  7. White/Brown
  8. Brown
T-568A vs T-568B wiring standard diagram
T-568A vs. T-568B ethernet standards wiring diagram.

Lay the wires flat and keep them in the correct order. Finally, flatten them gently with your thumb for easier insertion.

T-568B standard wired ethernet cable
My wires are arranged in the T-568B standard.

Use my RJ45 pinout tool as a quick reference for both the T-568A and T-568B standards.


Step 4: Trim Wires to Length

For non-passthrough connectors, trim the wires so that they are just long enough to reach the end of the connector when inserted. Cut them evenly so they line up perfectly.

For passthrough connectors, leave them a bit longer since the ends will protrude and be trimmed after crimping.


Step 5: Insert Wires Into the RJ45 Connector

Slide the wires into the connector carefully, ensuring they remain in the correct order. Push firmly until:

  • Each wire reaches the very end of the connector.
  • The outer jacket passes the strain relief tab for a strong connection.
wires in RJ45 connector

For passthrough connectors, the wires should stick out slightly from the other side.

As soon as you confirm the order, you’re ready to crimp.


Step 6: Crimp the Connector

Place the connector into the crimping tool and squeeze firmly until the pins press down into the wires and the strain relief tab locks onto the outer jacket.

crimping the RJ45 connector to the cable

Additionally, for passthrough connectors, trim the wire ends flush with the connector after crimping.

Then, repeat this entire process for the other end of the cable!


Step 7: Test Your Cable

Use a cable tester to confirm that all eight wires are connected in the correct order.

testing the ethernet cable with a cable tester

The lights on both ends should flash in sequence.

If any wires are misaligned, cut off the connector and repeat the process on that side.

Once confirmed, your custom ethernet cable is ready for use!


Cat6 vs Cat6a vs Cat5e: Which Should You Choose?

Not all Ethernet cables are created equal. Therefore, here’s a quick comparison to help you decide:

CategoryMaximum SpeedMaximum BandwidthMaximum Recommended LengthBest Use Case
Cat6Up to 1 Gbps (10 Gbps up to 55m)250 MHz100 mHome and small office networks, gaming, streaming
Cat6a10 Gbps up to 100m500 MHz100 mHigh-performance networks, data-heavy tasks, future-proofing
Cat5e1 Gbps100 MHz100 mBudget builds, basic home networking

Recommendation: Use Cat6 for most home setups, Cat6a if you want to future-proof or need maximum performance for longer runs, and Cat5e only if you already have it on hand or are working with very low-cost builds.


Frequently Asked Questions

Q: Can I mix T-568A on one end and T-568B on the other?
A: Only if you are intentionally creating a crossover cable. Otherwise, use the same wiring standard on both ends.

Q: How long can an Ethernet cable be?
A: Standard twisted-pair Ethernet cables (Cat5e, Cat6, Cat6a) are rated for up to 100 meters (328 feet) in total length. This includes patch cables at both ends. Beyond this length, you may experience signal loss or reduced speeds.

For 10 Gbps on Cat6, keep runs under 55 meters; use Cat6a for longer 10 Gbps runs.

Q: Do I really need a cable tester?
A: While optional, it saves time and frustration by catching miswires before you plug into your network.

Q: Should I ever use CCA cable?
A: No. Instead, always use solid copper cable for performance, safety, and compliance with Ethernet standards.


Troubleshooting Common Issues When Making Ethernet Cables

  • Tester Shows Miswired Pair: Re-check wiring order on both ends, re-crimp if needed.
  • Cable Doesn’t Click Securely: Ensure the strain relief tab is pressed down properly during crimping. Also ensure that the release tab covers on your strain relief boots aren’t too stiff and pressing down on the release tabs of the RJ45 connectors as a result. You may want to work the rubber of the strain relief boots with your thumbs a bit to stretch and break them in.
  • Poor Network Speeds: Test on another device and verify that you’re using solid copper cable, not CCA.

Final Remarks

Learning how to make ethernet cables saves money, eliminates clutter, and gives you full control over your network setup. Whether you’re wiring a home office, building a home lab, or just need a few short patch cables, this DIY approach is a game changer.

Practice a few times and you’ll be making professional-quality network cables in minutes!

If you prefer a video guide, you can watch my video guide below.

The post How to Make Ethernet Cables: A Complete Step-by-Step Guide appeared first on TechOpt.

]]>
https://www.techopt.io/servers-networking/how-to-make-ethernet-cables-a-complete-step-by-step-guide/feed 0
GPU Passthrough to Proxmox LXC Container for Plex (or Jellyfin) https://www.techopt.io/servers-networking/gpu-passthrough-to-proxmox-lxc-container-for-plex-or-jellyfin https://www.techopt.io/servers-networking/gpu-passthrough-to-proxmox-lxc-container-for-plex-or-jellyfin#respond Sun, 24 Aug 2025 20:40:06 +0000 https://www.techopt.io/?p=1059 When I added an Intel Arc GPU to my Proxmox server for Plex hardware transcoding, I quickly realized there isn’t much solid documentation on how to properly passthrough a GPU to a Proxmox LXC container. Most guides focus on VMs, not LXCs. After some trial and error, I figured out a process that works. These […]

The post GPU Passthrough to Proxmox LXC Container for Plex (or Jellyfin) appeared first on TechOpt.

]]>
When I added an Intel Arc GPU to my Proxmox server for Plex hardware transcoding, I quickly realized there isn’t much solid documentation on how to properly passthrough a GPU to a Proxmox LXC container. Most guides focus on VMs, not LXCs. After some trial and error, I figured out a process that works. These same steps can also apply if you’re running Jellyfin inside an LXC.

In this guide, I’ll walk you through enabling GPU passthrough in Proxmox (or Jellyfin) LXC step by step.

Step 1: Enabling PCI(e) Passthrough in Proxmox

The first step is enabling PCI passthrough at the Proxmox host level. I mostly followed the official documentation here: Proxmox PCI Passthrough Wiki.

I’ll summarize what should be done below.

Enable IOMMU in BIOS

Before you continue, enable IOMMU (Intel VT-d / AMD-Vi) in your system’s BIOS. This setting lets GPUs pass directly through to containers or VMs.

Each BIOS Is different, so if you’re not sure you should check your motherboard’s instruction manual.

Enable IOMMU Passthrough Mode

Not all hardware supports IOMMU passthrough, but if yours does you’ll see a big performance boost. Even if your system doesn’t, enabling it won’t cause problems, so it’s worth turning on.

Edit the GRUB configuration with:

nano /etc/default/grub

Locate the GRUB_CMDLINE_LINUX_DEFAULT line and add:

iommu=pt

Intel vs AMD Notes

  • On Intel CPUs with Proxmox older than v9 (kernel <6.8), also add: intel_iommu=on
  • On AMD CPUs, IOMMU is enabled by default.
  • On Intel CPUs with kernel 6.8 or newer (Proxmox 8 updated or Proxmox 9+), you don’t need the intel_iommu=on parameter.

With an AMD CPU on Proxmox 9, my file looked like this in the end:

grub config to passthrough gpu to proxmox lxc with iommu

Save the file by typing CTRL+X, typing Y to confirm and then Enter to save.

Then update grub by running:

update-grub

Load VFIO Kernel Modules

Next, we need to load the VFIO modules so the GPU can be bound for passthrough. Edit the modules file with:

nano /etc/modules

Add the following lines:

vfio
vfio_iommu_type1
vfio_pci

My file looked like this in the end:

added kernel modules needed for gpu passthrough to lxc in proxmox

Save and exit, then update initramfs:

update-initramfs -u -k all

Reboot and Verify

Reboot your Proxmox host and verify the modules are loaded:

lsmod | grep vfio

You should see the vfio modules listed. This is what my output looks like:

vfio kernel modules are loaded

If you don’t get any output, the kernel modules have not loaded correctly and you probably forgot to run the update-initramfs command above.

To double-check IOMMU is active, run:

dmesg | grep -e DMAR -e IOMMU -e AMD-Vi

Depending on your hardware, you should see confirmation that IOMMU or Directed I/O is enabled:

output when IOMMU is active (or similar)

Step 2: Finding the GPU Renderer Device Path

Now that PCI passthrough support is enabled, the next step is to figure out the device path of the renderer for the GPU you want to pass through.

Run the following on your Proxmox host:

ls /dev/dri

This will print all the detected GPUs. For example, my output looked like this:

by-path  card0  card1  renderD128  renderD129

If you only have a single GPU, you can usually assume it will be something like renderD128. But if you have multiple GPUs (as I did), you’ll need to identify which renderer belongs to your Intel Arc card.

First, run:

lspci

This will list all PCI devices. From there, I found my Intel Arc GPU at 0b:00.0:

lspci output showing my intel arc GPU card

Next, run:

ls -l /dev/dri/by-path/

My output looked like this:

lrwxrwxrwx 1 root root  8 Aug 24 11:54 pci-0000:04:00.0-card -> ../card0
lrwxrwxrwx 1 root root 13 Aug 24 11:54 pci-0000:04:00.0-render -> ../renderD129
lrwxrwxrwx 1 root root  8 Aug 24 11:54 pci-0000:0b:00.0-card -> ../card1
lrwxrwxrwx 1 root root 13 Aug 24 11:54 pci-0000:0b:00.0-render -> ../renderD128

From this, I confirmed that my Intel Arc GPU was associated with renderD128. That means the full device path I need to pass to my LXC container is:

/dev/dri/renderD128

Step 3: Passthrough GPU Device to the Plex LXC Container

Now that we know the correct device path, we can pass it through to the LXC container.

  1. Stop the container you want to pass the GPU into.
  2. In the Proxmox web UI, select your Plex LXC container.
  3. Go to Resources.
  4. At the top, click Add → Device Passthrough.
    steps to get to device passthrough menu
  5. In the popup, set Device Path to the GPU renderer path you identified in Step 2 (in my case, /dev/dri/renderD128).
  6. In the Access mode in CT field, type:0666
    add passthrough device to lxc config
  7. Click Add.
  8. Once added, you can start the container again.

A Note About Permissions

Normally, you would configure a proper UID or GID in CT for the render group inside the container so only that group has access. However, in my testing I wasn’t able to get the GPU working correctly with that method.

Using 0666 permissions allows read/write access for everyone. Since this is a GPU device node and not a directory containing files, I’m not too concerned, but it’s worth noting for anyone who takes their Linux permissions very seriously.

Step 4: Installing GPU Drivers Inside the LXC Container

With the GPU device passed through, the container now needs the proper drivers installed. This step varies depending on the Linux distribution you’re running inside the container.

Some distros may already include GPU drivers by default. But if you reach Step 5 and don’t see your GPU as an option in Plex (or Jellyfin), chances are you’re missing the driver inside your container.

In my case, I’m using a Debian container, which does not include Intel Arc drivers by default. Here’s what I did:

  1. Edit your apt sources to enable the non-free repo: nano /etc/apt/sources.list
  2. Add non-free to the end of each Debian repository line:
    my sources.list after adding the non-free Debian repository
  3. Refresh apt sources: apt update
  4. Install the Intel Arc driver package: apt install intel-media-va-driver-non-free
  5. Restart the container.

For Debian, I followed the official documentation here: Debian Hardware Video Acceleration Wiki.

Note: These steps will vary depending on your GPU make, model and container distribution. Make sure to check the official documentation for your hardware and distro.

Step 5: Enabling Hardware Rendering in Plex

Now that your GPU and drivers are ready, the final step is to enable hardware transcoding inside Plex.

  1. Open the Plex Web UI.
  2. Go to Settings (top-right corner).
  3. In the left sidebar, scroll down and click Transcoder under Settings.
  4. Make sure the following options are checked:
    • Use hardware acceleration when available
    • Use hardware-accelerated video encoding
  5. Under Hardware transcoding device, you should now see your GPU. If not, double-check Step 4. In my case, it showed up as Intel DG2 [Arc A380]
  6. Select your GPU and click Save Changes.
Steps to enable hardware encoding in plex ui

Testing Hardware Transcoding

To verify that hardware transcoding is working:

  1. Play back any movie or TV show.
  2. In the playback settings, change the quality to a lower resolution that forces Plex to transcode:
    Force Plex to transcode by selecting a lower quality
  3. While it’s playing, go to Settings → Dashboard.
  4. If the GPU is handling transcoding, you’ll see (hw) beside the stream being transcoded:
    The GPU passthrough to the proxmox lxc for plex can be confirmed working from Plex dashboard: here are the steps

That’s it! You’ve successfully set up GPU passthrough in Proxmox LXC for Plex. These same steps should also work for Jellyfin with minor adjustments for the Jellyfin UI.

The post GPU Passthrough to Proxmox LXC Container for Plex (or Jellyfin) appeared first on TechOpt.

]]>
https://www.techopt.io/servers-networking/gpu-passthrough-to-proxmox-lxc-container-for-plex-or-jellyfin/feed 0