Skip to content

Instantly share code, notes, and snippets.

@BeKnowDo
Last active July 29, 2026 14:21
Show Gist options
  • Select an option

  • Save BeKnowDo/087942808f0a0d7a157ba11b1b7416b0 to your computer and use it in GitHub Desktop.

Select an option

Save BeKnowDo/087942808f0a0d7a157ba11b1b7416b0 to your computer and use it in GitHub Desktop.
Fedora Developer Setup

Fedora 44 Cinnamon Developer Installation and Configuration Guide

Last updated: July 26, 2026

Target system: Fedora Linux 44 Cinnamon Spin, regular DNF-managed install, x86_64 desktop.

This guide consolidates the Fedora setup we worked through: developer tools, NVIDIA drivers, Docker, Docker Desktop, local AI tools, IDEs, Google Chrome, automatic mounting for internal storage drives, Steam gaming support, webcam controls, system monitoring, Postman, Slack, AppImage handling, and a Brother HL-L2405W printer.

Hardware profile this guide is tuned for:

  • CPU: AMD Ryzen 9 7900X
  • Memory: 128 GiB RAM
  • GPU: NVIDIA GeForce RTX 4060
  • Display: ultrawide 3440x1440, high refresh rate
  • Desktop: Cinnamon
  • Terminal: Terminator
  • Storage: multi-drive NVMe/SATA desktop
  • Network: Realtek 2.5 GbE plus Wi-Fi

Important: This guide targets the regular Fedora 44 Cinnamon Spin. It does not target an Atomic desktop. If you use an Atomic Fedora variant, adapt the DNF sections to rpm-ostree, Flatpak, and toolbox workflows.


1. Application inventory

This guide covers the following applications and tools.

Shell and developer base

  • Terminator terminal
  • Zsh
  • Oh My Zsh
  • Git and Git LFS
  • nvm
  • Node.js LTS
  • AWS CLI v2
  • AppImage support with FUSE

Browser

  • Google Chrome Stable

IDEs and developer apps

  • Visual Studio Code
  • Cursor IDE
  • Google Antigravity IDE
  • Postman

Containers

  • Docker Engine
  • Docker CLI
  • Docker Buildx
  • Docker Compose plugin
  • Docker Desktop
  • NVIDIA Container Toolkit for GPU containers

NVIDIA and graphics

  • RPM Fusion repositories
  • NVIDIA proprietary driver through akmod-nvidia
  • NVIDIA settings UI
  • Vulkan tools
  • OpenGL tools

AI and local models

  • LM Studio AppImage
  • LM Studio applications menu launcher

Communication

  • Slack

Gaming

  • Steam
  • Proton and Steam Play
  • GameMode
  • MangoHud
  • Gamescope

Hardware and utilities

  • Brother HL-L2405W printer setup
  • CUPS
  • Avahi printer discovery
  • Cameractrls
  • guvcview
  • OBS Studio
  • Mission Center
  • nvtop
  • btop

2. Install Fedora 44 Cinnamon

Download Fedora Cinnamon Spin 44 from the official Fedora Cinnamon Spin page:

https://fedoraproject.org/spins/cinnamon/download/

Use Fedora Media Writer to create the USB installer.

Suggested install choices:

  • Install type: fresh install
  • Desktop: Cinnamon
  • Filesystem: Btrfs for / and /home
  • Boot partition: ext4 is fine
  • Secure Boot: disabled for simplicity, or enabled with MOK enrollment later for NVIDIA
  • Hostname: something memorable, for example cesar-fedora

Before installing on a multi-drive machine, identify the target disk carefully:

lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,MOUNTPOINTS

Do not assume /dev/nvme0n1 is the install target. NVMe numbering can change.


3. First boot checklist

Open Terminator if it is already installed. If not, use the default Cinnamon terminal for the first few commands.

Verify the system:

cat /etc/fedora-release
uname -r
hostnamectl

Check the GPU is visible:

lspci | grep -Ei 'nvidia|vga|3d'

Create working directories:

mkdir -p "$HOME/Code" "$HOME/Applications" "$HOME/.local/bin"

Add ~/.local/bin to your shell path:

grep -q 'HOME/.local/bin' "$HOME/.profile" 2>/dev/null || \
  printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.profile"

Update Fedora immediately:

sudo dnf upgrade --refresh -y
sudo reboot

If Cinnamon blocks the reboot with a session inhibitor, save your work and run:

sudo systemctl reboot -i

You can inspect blockers with:

systemd-inhibit --list

3.1 Automatically mount additional internal drives

Your desktop has several NVMe and SATA drives. Configure each data partition with a persistent UUID rather than a path such as /dev/sda1 or /dev/nvme1n1p1. Kernel-assigned device names can change after hardware changes, firmware updates, or rebooting.

Important: The steps below mount an existing filesystem. They do not partition or format a drive. Do not run mkfs, fdisk, parted, or a formatting command on a drive that already contains data.

3.1.1 Inventory the drives and filesystems

List each disk, partition, filesystem type, label, UUID, model, and current mount point:

lsblk -e7 -o NAME,SIZE,FSTYPE,LABEL,UUID,MODEL,MOUNTPOINTS

Show additional filesystem identifiers:

sudo blkid

Show filesystems that are currently mounted:

findmnt --real

Select the partition that contains the filesystem, not merely the parent disk. For example, use a partition such as /dev/nvme0n1p1 or /dev/sda1, not /dev/nvme0n1 or /dev/sda.

If Cinnamon mounted the partition temporarily under /run/media/$USER/..., inspect and unmount it before creating the permanent mount:

findmnt -S /dev/DEVICE_PARTITION
udisksctl unmount -b /dev/DEVICE_PARTITION

Replace /dev/DEVICE_PARTITION with the real partition path.

3.1.2 Create permanent mount points

Use descriptive paths. These examples fit the storage roles commonly used on this workstation:

sudo mkdir -p /mnt/projects
sudo mkdir -p /mnt/models
sudo mkdir -p /mnt/archive

You only need to create the mount points you plan to use.

3.1.3 Record the UUID and filesystem type

For each partition, run:

sudo blkid -s UUID -s TYPE -o full /dev/DEVICE_PARTITION

Example output:

/dev/nvme0n1p1: UUID="11111111-2222-3333-4444-555555555555" TYPE="ext4"

Copy the UUID exactly. Also note the filesystem type, such as ext4, xfs, btrfs, ntfs, or exfat.

3.1.4 Back up and edit /etc/fstab

Create a timestamped backup before editing:

sudo cp -a /etc/fstab "/etc/fstab.backup.$(date +%Y%m%d-%H%M%S)"
sudoedit /etc/fstab

Add one line per filesystem. The following is an ext4 example:

UUID=11111111-2222-3333-4444-555555555555 /mnt/projects ext4 defaults,nofail,noatime,x-systemd.device-timeout=10s 0 2

Use the filesystem type reported by blkid. Common examples:

# ext4: use filesystem-check pass 2
UUID=REPLACE_WITH_UUID /mnt/projects ext4 defaults,nofail,noatime,x-systemd.device-timeout=10s 0 2

# XFS: use pass 0
UUID=REPLACE_WITH_UUID /mnt/models xfs defaults,nofail,noatime,x-systemd.device-timeout=10s 0 0

# Btrfs data filesystem: use pass 0
UUID=REPLACE_WITH_UUID /mnt/archive btrfs defaults,nofail,noatime,x-systemd.device-timeout=10s 0 0

The important options are:

  • nofail: continue booting if the drive is unavailable
  • noatime: avoid updating file access timestamps on every read
  • x-systemd.device-timeout=10s: avoid a long boot delay if the device is missing

For an internal NTFS or exFAT data partition, first obtain your numeric user and group IDs:

id -u
id -g

Then use those numeric values in the mount options. For a first Fedora desktop user, they are often 1000, but verify rather than assuming:

# NTFS using the in-kernel ntfs3 driver
UUID=REPLACE_WITH_UUID /mnt/shared ntfs3 defaults,nofail,uid=1000,gid=1000,umask=0022,x-systemd.device-timeout=10s 0 0

# exFAT
UUID=REPLACE_WITH_UUID /mnt/shared exfat defaults,nofail,uid=1000,gid=1000,umask=0022,x-systemd.device-timeout=10s 0 0

Do not add quotation marks around the UUID or mount point in /etc/fstab.

3.1.5 Validate the configuration before rebooting

Reload systemd's generated mount units, verify the file, and mount all newly configured filesystems:

sudo systemctl daemon-reload
sudo findmnt --verify --verbose
sudo mount -a

Confirm each mount:

findmnt /mnt/projects
df -hT /mnt/projects

Repeat those checks for /mnt/models, /mnt/archive, or any other mount points you created.

If sudo mount -a reports an error, correct /etc/fstab before rebooting. You can restore the timestamped backup if necessary.

3.1.6 Set ownership for Linux filesystems

For a newly mounted ext4, xfs, or btrfs data filesystem that should belong to your user:

sudo chown "$USER:$USER" /mnt/projects
sudo chmod 755 /mnt/projects

This changes only the root directory of the mounted filesystem. Avoid chown -R on an existing drive unless you intentionally want to rewrite ownership for every file.

3.1.7 Optional home-directory shortcuts

Create a symbolic link with a name that does not already exist:

ln -s /mnt/projects "$HOME/projects-drive"
ln -s /mnt/models "$HOME/models-drive"
ln -s /mnt/archive "$HOME/archive-drive"

Verify after a reboot:

findmnt --real
ls -ld /mnt/projects "$HOME/projects-drive"

4. Install Terminator

Install Terminator:

sudo dnf install -y terminator

Launch it:

terminator

Optional: set Terminator as your preferred terminal in Cinnamon.

Open:

System Settings > Preferred Applications

Set the terminal command to:

terminator

Most commands in the rest of this guide assume you are using Terminator.


5. Enable RPM Fusion

RPM Fusion is needed for common Fedora desktop extras, especially NVIDIA drivers and the native Steam package.

sudo dnf install -y \
  "https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm" \
  "https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm"

sudo dnf makecache --refresh

Verify:

dnf repolist | grep rpmfusion

You should see RPM Fusion free and nonfree repositories.


6. Install base developer packages

Install common tools used throughout the guide:

sudo dnf install -y \
  zsh git git-lfs curl wget unzip tar gzip ca-certificates \
  util-linux-user dnf-plugins-core \
  gcc gcc-c++ make cmake pkgconf-pkg-config openssl-devel \
  python3 python3-pip python3-devel \
  fuse fuse-libs libxcrypt-compat \
  xdg-utils desktop-file-utils \
  inxi fastfetch glx-utils vulkan-tools \
  ripgrep fd-find jq bat eza htop btop tree tmux neovim ShellCheck

Enable Git LFS:

git lfs install

Check AppImage support packages:

rpm -q fuse fuse-libs

7. Configure Git

Fedora's Git package is fine for normal development. It updates through DNF and avoids compiling Git from source.

Set your identity:

git config --global user.name "Cesar"
git config --global user.email "your-email@example.com"

Set defaults:

git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global core.editor "code --wait"
git config --global fetch.prune true
git config --global rerere.enabled true

Verify:

git --version
git lfs version
git config --global --list

8. Install Zsh and Oh My Zsh

Set Zsh as your default shell:

chsh -s "$(command -v zsh)"

Back up an existing Zsh config if present:

[ -f "$HOME/.zshrc" ] && cp "$HOME/.zshrc" "$HOME/.zshrc.backup.$(date +%Y%m%d%H%M%S)"

Install Oh My Zsh without starting a nested Zsh session:

RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Install useful plugins:

ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"

[ -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] || \
  git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"

[ -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] || \
  git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"

Enable plugins. Keep zsh-syntax-highlighting last:

if grep -q '^plugins=' "$HOME/.zshrc"; then
  sed -i 's/^plugins=(.*)/plugins=(git aws docker dnf npm zsh-autosuggestions zsh-syntax-highlighting)/' "$HOME/.zshrc"
else
  printf '\nplugins=(git aws docker dnf npm zsh-autosuggestions zsh-syntax-highlighting)\n' >> "$HOME/.zshrc"
fi

Add local bin to Zsh:

grep -q 'HOME/.local/bin' "$HOME/.zshrc" || \
  printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.zshrc"

Log out and log back in. Then verify:

echo "$SHELL"
zsh --version

9. Install nvm and Node.js LTS

Install nvm into your Zsh profile:

curl -fsSL -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | PROFILE="$HOME/.zshrc" bash

Open a new Terminator window, or source Zsh config:

source "$HOME/.zshrc"

Install Node.js LTS:

nvm install --lts
nvm alias default "lts/*"
node --version
npm --version

Enable Corepack for pnpm and Yarn support:

corepack enable

Optional: install the current Node release too:

nvm install node

Useful commands:

nvm ls
nvm current
nvm install --lts
nvm use --lts

10. Install AWS CLI v2

Install the official AWS CLI v2 package for Linux x86_64:

cd /tmp
rm -rf aws awscliv2.zip

curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip -q awscliv2.zip

sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

aws --version

Configure with SSO:

aws configure sso

Or configure classic access keys:

aws configure

Verify credentials:

aws sts get-caller-identity

11. Install NVIDIA drivers for RTX 4060

Use RPM Fusion packages. Do not use NVIDIA's .run installer unless you have a very specific reason.

11.1 Check Secure Boot

mokutil --sb-state

If Secure Boot is disabled, skip to section 11.3.

If Secure Boot is enabled, enroll a local Machine Owner Key so Fedora can load the locally built NVIDIA kernel module.

11.2 Secure Boot MOK enrollment

Install signing tools:

sudo dnf install -y akmods kmodtool mokutil openssl

Generate the akmods signing key if it does not exist:

sudo test -f /etc/pki/akmods/certs/public_key.der || sudo kmodgenca -a

Import the key:

sudo mokutil --import /etc/pki/akmods/certs/public_key.der

Create a temporary password when prompted. Then reboot:

sudo reboot

On the blue MOK screen:

  1. Choose Enroll MOK
  2. Choose Continue
  3. Choose Yes
  4. Enter the password you created
  5. Reboot

After booting back into Fedora, verify:

mokutil --test-key /etc/pki/akmods/certs/public_key.der

11.3 Install NVIDIA packages

sudo dnf install -y akmod-nvidia xorg-x11-drv-nvidia-cuda nvidia-settings

Mark the akmod package as user-installed so it is not accidentally removed later:

sudo dnf mark user akmod-nvidia

Build the module and regenerate initramfs:

sudo akmods --force
sudo dracut --force

If akmods complains about missing files for a specific kernel, install matching kernel development packages:

sudo dnf install -y "kernel-devel-$(uname -r)" kernel-headers
sudo akmods --kernels "$(uname -r)" --force
sudo dracut --force

If Fedora cannot find that older kernel-devel package, update into the newest kernel instead:

sudo dnf upgrade --refresh -y \
  kernel \
  kernel-core \
  kernel-modules \
  kernel-modules-core \
  kernel-devel

sudo reboot

Then build again after reboot:

sudo akmods --force
sudo dracut --force
sudo reboot

11.4 Verify NVIDIA after reboot

modinfo -F version nvidia
nvidia-smi
lsmod | grep '^nvidia'
glxinfo -B | grep -E 'OpenGL vendor|OpenGL renderer'
vulkaninfo --summary | grep -Ei 'deviceName|driverName' || true

Expected result:

  • nvidia-smi shows the NVIDIA GeForce RTX 4060
  • lsmod shows nvidia, nvidia_modeset, nvidia_drm, and often nvidia_uvm
  • OpenGL renderer mentions NVIDIA, not llvmpipe
  • Vulkan lists the NVIDIA GPU

Enable NVIDIA suspend and resume services:

sudo systemctl enable nvidia-suspend.service
sudo systemctl enable nvidia-hibernate.service
sudo systemctl enable nvidia-resume.service

11.5 Ignore harmless Vulkan warnings when NVIDIA still works

You may see warnings like this from vulkaninfo:

libvulkan_dzn.so ... Skipping this driver

If vulkaninfo still lists deviceName = NVIDIA GeForce RTX 4060 and driverName = NVIDIA, the NVIDIA Vulkan path is working. The warning is not worth chasing unless a game or app fails.


12. Install Docker Engine and Docker Compose

This uses Docker's official Fedora repository.

12.1 Remove conflicting packages

for pkg in \
  docker \
  docker-client \
  docker-client-latest \
  docker-common \
  docker-latest \
  docker-latest-logrotate \
  docker-logrotate \
  docker-selinux \
  docker-engine-selinux \
  docker-engine \
  podman-docker; do
  sudo dnf remove -y "$pkg" 2>/dev/null || true
done

12.2 Add Docker's Fedora repository

sudo dnf install -y dnf-plugins-core

sudo dnf config-manager addrepo \
  --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo

sudo dnf makecache --refresh

Verify:

dnf repolist | grep -i docker

12.3 Install Docker Engine, Buildx, and Compose

sudo dnf install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

When prompted for Docker's GPG key, verify this fingerprint:

060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35

Start Docker:

sudo systemctl enable --now docker
sudo systemctl status docker --no-pager

12.4 Let your user run Docker without sudo

Security note: membership in the docker group effectively grants root-level control of the machine.

sudo usermod -aG docker "$USER"

Apply the group change by logging out and back in. For a quick terminal-only refresh:

newgrp docker

Verify:

groups
docker run hello-world
docker compose version

12.5 Tiny Compose smoke test

mkdir -p "$HOME/Code/docker-smoke-test"
cd "$HOME/Code/docker-smoke-test"

cat > compose.yaml <<'YAML'
services:
  hello:
    image: hello-world
YAML

docker compose up

docker compose down --remove-orphans
cd "$HOME"
rm -rf "$HOME/Code/docker-smoke-test"

13. Install NVIDIA Container Toolkit

Only do this after nvidia-smi works on the host.

Add NVIDIA's repository:

curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \
  sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo

Install the toolkit:

sudo dnf install -y nvidia-container-toolkit

Configure Docker:

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Test GPU access in a container:

docker run --rm --gpus all ubuntu nvidia-smi

If Docker permission fails:

sudo docker run --rm --gpus all ubuntu nvidia-smi

14. Install Docker Desktop

Docker Desktop can coexist with Docker Engine. It uses a separate desktop-linux Docker context and stores its data separately inside a VM.

Important Fedora 44 note: Docker's current Fedora Desktop docs may lag behind Fedora releases. At the time this guide was written, Docker Desktop's Fedora page listed Fedora 42 and Fedora 43, while Docker Engine listed Fedora 44. Docker Desktop may still work on Fedora 44, but Docker Engine is the safer base install.

14.1 Install Desktop requirements

Docker Desktop uses KVM. On Cinnamon, install gnome-terminal too. You can still use Terminator day to day, but Docker Desktop expects gnome-terminal for terminal access from the UI.

sudo dnf install -y \
  gnome-terminal \
  qemu qemu-kvm \
  virt-manager virt-install libvirt libvirt-daemon-kvm \
  pass gnupg2

Check KVM:

lsmod | grep kvm

For the Ryzen 9 7900X, you should see kvm_amd. If not:

sudo modprobe kvm
sudo modprobe kvm_amd

Add yourself to the kvm group:

sudo usermod -aG kvm "$USER"

Reboot or log out and back in:

sudo systemctl reboot -i

Verify:

groups
ls -l /dev/kvm

14.2 Download and install Docker Desktop RPM

mkdir -p "$HOME/Downloads"
cd "$HOME/Downloads"

curl -L -o docker-desktop-x86_64.rpm \
  "https://desktop.docker.com/linux/main/amd64/docker-desktop-x86_64.rpm"

sudo dnf install -y ./docker-desktop-x86_64.rpm

14.3 Launch Docker Desktop

Start from Terminator:

systemctl --user start docker-desktop

Or launch it from the Cinnamon applications menu:

Applications > Docker Desktop

Accept the Docker Desktop terms when prompted. Docker Desktop will not run until you accept them.

Enable start on sign-in:

systemctl --user enable docker-desktop

Verify contexts:

docker context ls
docker context show

Switch to Docker Desktop:

docker context use desktop-linux
docker run hello-world

Switch back to local Docker Engine:

docker context use default

14.4 Terminator aliases for Docker Desktop

Add these to ~/.zshrc:

cat >> "$HOME/.zshrc" <<'EOF_ZSH'

# Docker Desktop helpers
alias ddesktop-start='systemctl --user start docker-desktop'
alias ddesktop-stop='systemctl --user stop docker-desktop'
alias ddesktop-status='systemctl --user status docker-desktop'
alias ddesktop-use='docker context use desktop-linux'
alias docker-engine-use='docker context use default'
alias docker-context='docker context ls'
EOF_ZSH

source "$HOME/.zshrc"

15. Install Google Chrome

Google provides a 64-bit RPM package for Fedora. Installing the RPM also configures Google's Chrome repository so Chrome can receive future updates through DNF.

15.1 Download and install the official RPM

mkdir -p "$HOME/Downloads"
cd "$HOME/Downloads"

curl -fL \
  "https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm" \
  -o google-chrome-stable_current_x86_64.rpm

sudo dnf install -y ./google-chrome-stable_current_x86_64.rpm

Verify the package, executable, and repository:

rpm -q google-chrome-stable
google-chrome-stable --version
dnf repolist | grep -i google-chrome

Launch Chrome:

google-chrome-stable

Chrome should also appear in the Cinnamon applications menu as Google Chrome.

15.2 Optional: make Chrome the default browser

Use Cinnamon's graphical settings:

System Settings > Preferred Applications > Web

Or set it from the terminal:

xdg-settings set default-web-browser google-chrome.desktop
xdg-settings get default-web-browser

15.3 Troubleshooting

If the downloaded RPM is incomplete or DNF rejects it, remove it and download it again:

rm -f "$HOME/Downloads/google-chrome-stable_current_x86_64.rpm"
cd "$HOME/Downloads"

curl -fL \
  "https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm" \
  -o google-chrome-stable_current_x86_64.rpm

sudo dnf install -y ./google-chrome-stable_current_x86_64.rpm

If Chrome's repository exists but is disabled, inspect it:

sudo cat /etc/yum.repos.d/google-chrome.repo
dnf repolist --all | grep -i google-chrome

16. Install Visual Studio Code

Add Microsoft's RPM repository:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc

sudo tee /etc/yum.repos.d/vscode.repo > /dev/null <<'REPO'
[code]
name=Visual Studio Code
baseurl=https://packages.microsoft.com/yumrepos/vscode
enabled=1
autorefresh=1
type=rpm-md
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
REPO

sudo dnf makecache
sudo dnf install -y code

Verify:

code --version

Optional extensions:

code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
code --install-extension ms-azuretools.vscode-docker
code --install-extension amazonwebservices.aws-toolkit-vscode
code --install-extension github.vscode-github-actions

17. Install Cursor IDE

If your system already has the Cursor repository configured:

sudo dnf makecache
sudo dnf install -y cursor

If Fedora cannot find the package, open the download page:

xdg-open https://cursor.com/download

Download the Linux RPM for x64. Then install the newest Cursor RPM from ~/Downloads:

CURSOR_RPM="$(find "$HOME/Downloads" -maxdepth 1 -type f \( -iname '*cursor*.rpm' -o -iname '*Cursor*.rpm' \) | sort | tail -n 1)"

test -n "$CURSOR_RPM" || { echo "Download the Cursor RPM first."; exit 1; }

sudo dnf install -y "$CURSOR_RPM"

Verify:

command -v cursor || true
cursor --version 2>/dev/null | head -n 2 || true

18. Install Google Antigravity IDE

Add the Antigravity RPM repository:

sudo tee /etc/yum.repos.d/antigravity.repo > /dev/null <<'REPO'
[antigravity-rpm]
name=Antigravity RPM Repository
baseurl=https://us-central1-yum.pkg.dev/projects/antigravity-auto-updater-dev/antigravity-rpm
enabled=1
gpgcheck=0
REPO

sudo dnf makecache
sudo dnf install -y antigravity

Note: Google's RPM instructions have used gpgcheck=0. Revisit this if Google publishes a signed RPM repository key later.

Verify:

command -v antigravity || true
antigravity --version 2>/dev/null | head -n 2 || true

19. Install Slack

Preferred path: install the official Linux RPM from Slack's download page.

Open the page:

xdg-open https://slack.com/downloads/linux

Download the RPM. Then install it:

SLACK_RPM="$(find "$HOME/Downloads" -maxdepth 1 -type f -iname 'slack-*.rpm' | sort | tail -n 1)"

test -n "$SLACK_RPM" || { echo "Download the Slack RPM first."; exit 1; }

sudo dnf install -y "$SLACK_RPM"

If the Slack repo is already configured:

sudo dnf install -y slack

Flatpak fallback:

flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub com.slack.Slack
flatpak run com.slack.Slack

Use either RPM Slack or Flatpak Slack. Do not install both unless you intentionally want two copies.


20. Install Postman

Use the official tarball method.

cd /tmp

curl -L -o postman-linux-x64.tar.gz \
  https://dl.pstmn.io/download/latest/linux64

sudo rm -rf /opt/Postman
sudo tar -xzf postman-linux-x64.tar.gz -C /opt

sudo ln -sfn /opt/Postman/Postman /usr/local/bin/postman

Test:

postman

Create an applications menu launcher:

mkdir -p "$HOME/.local/share/applications"

cat > "$HOME/.local/share/applications/postman.desktop" <<'DESKTOP'
[Desktop Entry]
Name=Postman
Comment=API development environment
Exec=/opt/Postman/Postman
Icon=/opt/Postman/app/resources/app/assets/icon.png
Terminal=false
Type=Application
Categories=Development;Network;
StartupWMClass=Postman
DESKTOP

update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true

Optional Zsh alias:

cat >> "$HOME/.zshrc" <<'EOF_ZSH'

# Postman
alias postman='/opt/Postman/Postman'
EOF_ZSH

source "$HOME/.zshrc"

To update Postman later, rerun the tarball commands.


21. Install LM Studio with an applications menu launcher

LM Studio for Linux is available as an AppImage. Keep it in ~/Applications and create a .desktop launcher.

20.1 Install AppImage support

sudo dnf install -y fuse fuse-libs

20.2 Download LM Studio

Open the official download page:

xdg-open "https://lmstudio.ai/download?os=linux"

Download the Linux x64 AppImage.

20.3 Move and make executable

mkdir -p "$HOME/Applications"

LM_APPIMAGE="$(find "$HOME/Downloads" -maxdepth 1 -type f \( -iname '*LM*Studio*.AppImage' -o -iname '*LMStudio*.AppImage' \) | sort | tail -n 1)"

echo "$LM_APPIMAGE"

test -n "$LM_APPIMAGE" || { echo "Download the LM Studio AppImage first."; exit 1; }

mv "$LM_APPIMAGE" "$HOME/Applications/LM-Studio.AppImage"
chmod +x "$HOME/Applications/LM-Studio.AppImage"

Test:

"$HOME/Applications/LM-Studio.AppImage"

20.4 Create Cinnamon applications menu launcher

mkdir -p "$HOME/.local/share/applications"

cat > "$HOME/.local/share/applications/lm-studio.desktop" <<DESKTOP
[Desktop Entry]
Name=LM Studio
Comment=Run local LLMs on your computer
Exec=$HOME/Applications/LM-Studio.AppImage
Terminal=false
Type=Application
Categories=Development;Utility;AI;
StartupWMClass=LM Studio
DESKTOP

chmod +x "$HOME/.local/share/applications/lm-studio.desktop"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true

Search the Cinnamon applications menu for:

LM Studio

If it does not appear immediately, log out and log back in.

20.5 Optional terminal command

mkdir -p "$HOME/.local/bin"
ln -sfn "$HOME/Applications/LM-Studio.AppImage" "$HOME/.local/bin/lmstudio"

grep -q 'export PATH="$HOME/.local/bin:$PATH"' "$HOME/.zshrc" || \
  echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.zshrc"

source "$HOME/.zshrc"

Test:

lmstudio

22. AppImage general pattern

For any AppImage:

sudo dnf install -y fuse fuse-libs
mkdir -p "$HOME/Applications"

mv "$HOME/Downloads/MyApp.AppImage" "$HOME/Applications/"
chmod +x "$HOME/Applications/MyApp.AppImage"
"$HOME/Applications/MyApp.AppImage"

Create a launcher:

mkdir -p "$HOME/.local/share/applications"

cat > "$HOME/.local/share/applications/myapp.desktop" <<'DESKTOP'
[Desktop Entry]
Name=My App
Comment=AppImage application
Exec=/home/cesar/Applications/MyApp.AppImage
Terminal=false
Type=Application
Categories=Development;Utility;
DESKTOP

update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true

Replace My App and MyApp.AppImage with the real app name and file name.

If the AppImage fails with a FUSE error:

sudo dnf reinstall -y fuse fuse-libs

If it still fails, try extracting it:

cd "$HOME/Applications"
./MyApp.AppImage --appimage-extract
./squashfs-root/AppRun

23. Install Steam and gaming tools

22.1 Native RPM install through RPM Fusion

sudo dnf install -y steam

If RPM Fusion picks a bad mirror and times out, use the troubleshooting section near the end of this guide.

Launch Steam:

steam

22.2 Flatpak fallback

If RPM Fusion is having mirror problems:

flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub com.valvesoftware.Steam
flatpak run com.valvesoftware.Steam

22.3 Enable Steam Play and Proton

In Steam:

Steam > Settings > Compatibility

Enable:

Enable Steam Play for supported titles
Enable Steam Play for all other titles

22.4 Install GameMode, MangoHud, and Gamescope

sudo dnf install -y gamemode mangohud gamescope

Per-game launch options:

gamemoderun %command%

With MangoHud:

mangohud gamemoderun %command%

Verify GameMode while a game is running:

gamemoded -s

24. Install system monitoring tools

23.1 Mission Center GUI

Mission Center is the best all-in-one GUI monitor for CPU, RAM, disk, network, processes, and GPU stats.

flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub io.missioncenter.MissionCenter

Launch:

flatpak run io.missioncenter.MissionCenter

Or search the applications menu for:

Mission Center

23.2 Terminal monitors

sudo dnf install -y nvtop btop

Use:

nvtop
btop

Recommended pattern:

Mission Center = daily GUI monitor
nvtop = NVIDIA GPU monitor in the terminal
btop = CPU, RAM, disks, network, and processes in the terminal

25. Install camera controls

Your EMEET camera uses the standard Linux uvcvideo stack, so V4L2 camera tools are the right starting point.

24.1 Install Cameractrls

flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub hu.irl.cameractrls

Launch:

flatpak run hu.irl.cameractrls

In the Cinnamon applications menu, search for:

Camera Controls

If it does not show up:

update-desktop-database ~/.local/share/flatpak/exports/share/applications 2>/dev/null || true
update-desktop-database /var/lib/flatpak/exports/share/applications 2>/dev/null || true

Then log out and log back in.

Manual launcher fallback:

mkdir -p "$HOME/.local/share/applications"

cat > "$HOME/.local/share/applications/cameractrls.desktop" <<'DESKTOP'
[Desktop Entry]
Name=Camera Controls
Comment=Control webcam settings
Exec=flatpak run hu.irl.cameractrls
Terminal=false
Type=Application
Categories=AudioVideo;Video;Settings;
DESKTOP

update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true

24.2 Install command-line camera tools

sudo dnf install -y v4l-utils

List cameras:

v4l2-ctl --list-devices

List controls:

v4l2-ctl --list-ctrls

Inspect a camera:

v4l2-ctl -d /dev/video0 --all

Example manual controls:

v4l2-ctl -d /dev/video0 --set-ctrl=brightness=128
v4l2-ctl -d /dev/video0 --set-ctrl=contrast=128
v4l2-ctl -d /dev/video0 --set-ctrl=saturation=128

Exact control names depend on the webcam.

24.3 Install guvcview and OBS Studio

sudo dnf install -y guvcview obs-studio

Use:

guvcview
obs

Recommended pattern:

Cameractrls = daily camera control panel
guvcview = quick live preview and fallback controls
OBS Studio = recording, streaming, filters, and virtual camera
v4l2-ctl = troubleshooting and scripting

26. Set up Brother HL-L2405W printer

Try driverless AirPrint/IPP first. Brother's Linux page for this class of printer recommends AirPrint when available.

25.1 Install printing tools

sudo dnf install -y cups cups-client cups-filters system-config-printer avahi nss-mdns avahi-tools

Enable services:

sudo systemctl enable --now cups
sudo systemctl enable --now avahi-daemon

25.2 Connect the printer

For Wi-Fi, connect the Brother HL-L2405W to the same network as your Fedora machine.

For USB, plug the printer directly into the machine.

25.3 Discover the printer

lpinfo -v | grep -i brother || true
driverless || true
avahi-browse -rt _ipp._tcp

25.4 Add with the GUI

system-config-printer

Then:

  1. Click Add
  2. Select the Brother printer if it appears
  3. Prefer a driverless, AirPrint, or IPP option
  4. Name it Brother_HL_L2405W
  5. Print a test page

25.5 Add with command line

List devices:

lpinfo -v

If you see an IPP URI, use it:

sudo lpadmin -p Brother_HL_L2405W \
  -E \
  -v "PASTE_PRINTER_URI_HERE" \
  -m everywhere

sudo lpoptions -d Brother_HL_L2405W

Example by IP address:

sudo lpadmin -p Brother_HL_L2405W \
  -E \
  -v "ipp://192.168.1.75/ipp/print" \
  -m everywhere

sudo lpoptions -d Brother_HL_L2405W

Test:

lpstat -p -d
echo "Brother HL-L2405W Fedora test page" | lp -d Brother_HL_L2405W

25.6 Brother RPM installer fallback

Only use this if driverless IPP does not work.

Open Brother's support page:

xdg-open "https://support.brother.com/g/b/downloadtop.aspx?c=us&lang=en&prod=hll2405w_us"

Choose Linux RPM. Download the Linux driver installer, then run:

cd "$HOME/Downloads"
ls -lh linux-brprinter-installer*.gz

gunzip linux-brprinter-installer*.gz
sudo bash linux-brprinter-installer-* HLL2405W

When prompted for DeviceURI:

  • USB: choose N
  • Wi-Fi or Ethernet: choose Y, then specify the printer IP address

27. Flatpak app menu refresh

If a Flatpak app installs but does not appear in Cinnamon's menu:

flatpak list
find ~/.local/share/flatpak /var/lib/flatpak -name '*.desktop' 2>/dev/null | grep -Ei 'camera|steam|slack|mission|postman|studio' || true

update-desktop-database ~/.local/share/flatpak/exports/share/applications 2>/dev/null || true
update-desktop-database /var/lib/flatpak/exports/share/applications 2>/dev/null || true

Then log out and log back in.

You can always launch a Flatpak directly:

flatpak run hu.irl.cameractrls
flatpak run io.missioncenter.MissionCenter
flatpak run com.valvesoftware.Steam
flatpak run com.slack.Slack

28. Repair missing CA bundle path

Use this if DNF or curl shows an error like:

Curl error (77): Problem with the SSL CA cert
error adding trust anchors from file: /etc/pki/tls/certs/ca-bundle.crt

First check:

ls -l /etc/pki/tls/certs/ca-bundle.crt
ls -l /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

If /etc/pki/tls/certs/ca-bundle.crt is missing but /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem exists, recreate the compatibility symlink:

sudo mkdir -p /etc/pki/tls/certs
sudo rm -f /etc/pki/tls/certs/ca-bundle.crt

sudo ln -s \
  /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
  /etc/pki/tls/certs/ca-bundle.crt

sudo update-ca-trust extract

Verify:

ls -l /etc/pki/tls/certs/ca-bundle.crt
readlink -f /etc/pki/tls/certs/ca-bundle.crt
test -r /etc/pki/tls/certs/ca-bundle.crt && echo "CA bundle is readable"

Test HTTPS:

curl -I https://packagecloud.io
curl -I https://slack.com
curl -I https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64/repodata/repomd.xml

Then refresh DNF:

sudo dnf clean all
sudo dnf makecache --refresh

Do not use this command on Fedora if it errors:

sudo update-ca-trust force-enable

On your Fedora install, force-enable was not a valid update-ca-trust command. sudo update-ca-trust extract is the command you need.


29. Work around slow RPM Fusion mirrors

Use this if DNF times out on a mirror like:

edgeuno-bog2.mm.fcix.net

Clean the cache and retry with longer timeouts:

sudo dnf clean all
sudo rm -rf /var/cache/dnf /var/cache/libdnf5

sudo dnf \
  --refresh \
  --setopt=timeout=180 \
  --setopt=retries=20 \
  --setopt=minrate=1 \
  makecache --refresh

Retry the install:

sudo dnf \
  --refresh \
  --setopt=timeout=180 \
  --setopt=retries=20 \
  --setopt=minrate=1 \
  install -y steam

For packages that do not need RPM Fusion, bypass RPM Fusion temporarily:

sudo dnf install -y cursor --disablerepo='rpmfusion-*'
sudo dnf install -y ./docker-desktop-x86_64.rpm --disablerepo='rpmfusion-*'

Optional: make RPM Fusion failures non-fatal during unrelated installs:

sudo dnf config-manager setopt rpmfusion-free.skip_if_unavailable=1
sudo dnf config-manager setopt rpmfusion-free-updates.skip_if_unavailable=1
sudo dnf config-manager setopt rpmfusion-nonfree.skip_if_unavailable=1
sudo dnf config-manager setopt rpmfusion-nonfree-updates.skip_if_unavailable=1

30. Final verification script

Run this from a fresh Terminator session:

cat > /tmp/verify-fedora-cinnamon-dev-env.sh <<'VERIFY'
#!/usr/bin/env bash
set -u

section() {
  printf '\n== %s ==\n' "$1"
}

section "System"
cat /etc/fedora-release || true
uname -r || true
hostnamectl | sed -n '1,12p' || true

section "Storage mounts"
lsblk -e7 -o NAME,SIZE,FSTYPE,LABEL,UUID,MODEL,MOUNTPOINTS || true
findmnt --real || true
findmnt --verify --verbose || true

section "Desktop"
echo "XDG_CURRENT_DESKTOP=${XDG_CURRENT_DESKTOP:-unknown}"
echo "DESKTOP_SESSION=${DESKTOP_SESSION:-unknown}"

section "Shell"
echo "SHELL=$SHELL"
zsh --version || true

section "Terminator"
command -v terminator || true
terminator --version 2>/dev/null || true

section "Git"
git --version || true
git lfs version || true

section "AWS CLI"
aws --version || true

section "Node via nvm"
zsh -ic 'command -v nvm && nvm --version && node --version && npm --version' || true

section "NVIDIA"
modinfo -F version nvidia 2>/dev/null || true
nvidia-smi || true
lsmod | grep '^nvidia' || true
glxinfo -B 2>/dev/null | grep -E 'OpenGL vendor|OpenGL renderer' || true
vulkaninfo --summary 2>/dev/null | grep -Ei 'deviceName|driverName' || true

section "Docker Engine"
docker --version || true
docker compose version || true
docker context ls || true

section "NVIDIA Container Toolkit"
command -v nvidia-ctk || true
rpm -q nvidia-container-toolkit 2>/dev/null || true

section "Docker Desktop"
systemctl --user status docker-desktop --no-pager 2>/dev/null | sed -n '1,12p' || true

section "Google Chrome"
command -v google-chrome-stable || true
google-chrome-stable --version 2>/dev/null || true
rpm -q google-chrome-stable 2>/dev/null || true

section "VS Code"
code --version 2>/dev/null | head -n 2 || true

section "Cursor"
command -v cursor || true
cursor --version 2>/dev/null | head -n 2 || true

section "Antigravity"
command -v antigravity || true
antigravity --version 2>/dev/null | head -n 2 || true

section "Postman"
command -v postman || true
ls /opt/Postman/Postman 2>/dev/null || true

section "LM Studio"
ls "$HOME/Applications"/*Studio*.AppImage 2>/dev/null || true
ls "$HOME/.local/share/applications"/*lm*studio*.desktop 2>/dev/null || true

section "Slack"
command -v slack || true
slack --version 2>/dev/null || true
flatpak list 2>/dev/null | grep -i slack || true

section "Steam and gaming"
command -v steam || true
flatpak list 2>/dev/null | grep -i steam || true
command -v gamemoderun || true
command -v mangohud || true
command -v gamescope || true

section "Monitoring"
command -v nvtop || true
command -v btop || true
flatpak list 2>/dev/null | grep -i mission || true

section "Camera"
command -v v4l2-ctl || true
flatpak list 2>/dev/null | grep -i camera || true
command -v guvcview || true
command -v obs || true

section "Printer"
lpstat -t 2>/dev/null || true
VERIFY

bash /tmp/verify-fedora-cinnamon-dev-env.sh

31. Maintenance and updates

Update Fedora packages, including Google Chrome from its configured repository:

sudo dnf upgrade --refresh -y

Update only Google Chrome when needed:

sudo dnf upgrade --refresh -y google-chrome-stable
google-chrome-stable --version

Update Oh My Zsh:

omz update

Update Node LTS:

nvm install --lts
nvm alias default "lts/*"

Update AWS CLI v2:

cd /tmp
rm -rf aws awscliv2.zip
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip -q awscliv2.zip
sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
aws --version

Update Postman:

cd /tmp
curl -L -o postman-linux-x64.tar.gz https://dl.pstmn.io/download/latest/linux64
sudo rm -rf /opt/Postman
sudo tar -xzf postman-linux-x64.tar.gz -C /opt
sudo ln -sfn /opt/Postman/Postman /usr/local/bin/postman

Update LM Studio AppImage:

  1. Download the newest Linux x64 AppImage from LM Studio.
  2. Replace the existing file:
LM_APPIMAGE="$(find "$HOME/Downloads" -maxdepth 1 -type f \( -iname '*LM*Studio*.AppImage' -o -iname '*LMStudio*.AppImage' \) | sort | tail -n 1)"

test -n "$LM_APPIMAGE" || { echo "Download the new LM Studio AppImage first."; exit 1; }

install -Dm755 "$LM_APPIMAGE" "$HOME/Applications/LM-Studio.AppImage"

Update Docker Desktop:

cd "$HOME/Downloads"
curl -L -o docker-desktop-x86_64.rpm \
  "https://desktop.docker.com/linux/main/amd64/docker-desktop-x86_64.rpm"

sudo dnf remove -y docker-desktop
sudo dnf install -y ./docker-desktop-x86_64.rpm

After Fedora kernel updates, the NVIDIA module should rebuild through akmods. If the NVIDIA driver fails after reboot:

sudo akmods --force
sudo dracut --force
sudo reboot

32. Quick run order for a fresh install

Use this order on a fresh Fedora 44 Cinnamon install:

  1. Install Fedora 44 Cinnamon and update the system
  2. Inventory the internal disks and configure UUID-based automatic mounts
  3. Install Terminator
  4. Enable RPM Fusion
  5. Install base developer packages
  6. Configure Git
  7. Install Zsh and Oh My Zsh
  8. Install nvm and Node.js LTS
  9. Install AWS CLI v2
  10. Install NVIDIA drivers and reboot
  11. Install Docker Engine and Compose
  12. Install NVIDIA Container Toolkit if you need GPU containers
  13. Install Docker Desktop if you want the GUI
  14. Install Google Chrome
  15. Install VS Code, Cursor, Antigravity, and Postman
  16. Install Slack
  17. Install LM Studio AppImage and launcher
  18. Install Steam, Proton support, GameMode, MangoHud, and Gamescope
  19. Install Mission Center, nvtop, and btop
  20. Install camera tools
  21. Set up the Brother printer
  22. Run the final verification script

33. References


34. Install and Configure Nginx on Fedora 43 for a DigitalOcean Droplet

These notes are for a Fedora 43 DigitalOcean Droplet. Fedora installs Nginx from the standard DNF repositories, uses systemd to manage the service, and loads additional site configs from /etc/nginx/conf.d/*.conf.

This section covers:

  • Updating Fedora
  • Installing Nginx
  • Starting and enabling the service
  • Opening the Fedora firewall
  • Checking DigitalOcean Cloud Firewall rules
  • Creating a basic website directory
  • Configuring an Nginx server block
  • Testing and reloading Nginx
  • Pointing DNS to the Droplet
  • Installing HTTPS with Certbot
  • Viewing logs
  • Setting up a reverse proxy
  • Troubleshooting common issues

33.1 SSH into the Droplet

Use the IP address from your DigitalOcean Droplet dashboard.

ssh root@YOUR_DROPLET_IP

Or, if you created a sudo user:

ssh cesar@YOUR_DROPLET_IP

33.2 Update Fedora

Before installing Nginx, update the system packages.

sudo dnf upgrade --refresh -y

If the update installs a new kernel or a large number of system packages, reboot before continuing.

sudo reboot

After the Droplet comes back online, reconnect:

ssh root@YOUR_DROPLET_IP

Or:

ssh cesar@YOUR_DROPLET_IP

33.3 Install Nginx

Install Nginx from Fedora's package repositories.

sudo dnf install -y nginx

Confirm that Nginx installed correctly:

nginx -v
rpm -q nginx

33.4 Enable and Start Nginx

Enable Nginx so it starts automatically on boot:

sudo systemctl enable nginx

Start Nginx now:

sudo systemctl start nginx

Or enable and start it in one command:

sudo systemctl enable --now nginx

Check the service status:

sudo systemctl status nginx --no-pager

You should see something like:

Active: active (running)

33.5 Open HTTP and HTTPS in the Fedora Firewall

Fedora commonly uses firewalld. If your Droplet uses firewalld, allow HTTP and HTTPS traffic.

Check whether firewalld is running:

sudo systemctl status firewalld --no-pager

If it is not installed or not running, install and enable it:

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld

Allow HTTP and HTTPS:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Verify the rules:

sudo firewall-cmd --query-service=http
sudo firewall-cmd --query-service=https

Both should return:

yes

You can also list the active firewall configuration:

sudo firewall-cmd --list-all

33.6 Check the DigitalOcean Cloud Firewall

DigitalOcean Cloud Firewalls are separate from the firewall inside the Droplet. If you use both, both need to allow the traffic.

In the DigitalOcean dashboard, make sure the Cloud Firewall attached to your Droplet allows the following inbound rules:

Type Protocol Port Source
SSH TCP 22 Your IP, or 0.0.0.0/0 if needed
HTTP TCP 80 0.0.0.0/0, ::/0
HTTPS TCP 443 0.0.0.0/0, ::/0

Be careful not to lock yourself out of SSH while changing firewall rules.

33.7 Test the Default Nginx Page

From your local machine, visit:

http://YOUR_DROPLET_IP

Or test with curl:

curl -I http://YOUR_DROPLET_IP

A working response should look similar to:

HTTP/1.1 200 OK
Server: nginx

33.8 Create a Basic Website Directory

Replace example.com with your real domain.

sudo mkdir -p /var/www/example.com/html

Create a simple test page:

sudo tee /var/www/example.com/html/index.html > /dev/null <<'HTML'
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>example.com</title>
</head>
<body>
  <h1>Nginx is working on Fedora 43</h1>
</body>
</html>
HTML

Set ownership:

sudo chown -R nginx:nginx /var/www/example.com

Set reasonable permissions:

sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;

33.9 Add SELinux Context for the Site Directory

Fedora uses SELinux. If you create a custom web root like /var/www/example.com, give it the correct web content context.

Install the SELinux management tools if needed:

sudo dnf install -y policycoreutils-python-utils

Add the correct SELinux context:

sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com

33.10 Create an Nginx Server Block

Fedora's Nginx package loads extra site configs from:

/etc/nginx/conf.d/*.conf

This is different from the Debian or Ubuntu style sites-available and sites-enabled layout.

Create the site config:

sudo nano /etc/nginx/conf.d/example.com.conf

Add this configuration:

server {
  listen 80;
  listen [::]:80;

  server_name example.com www.example.com;

  root /var/www/example.com/html;
  index index.html;

  access_log /var/log/nginx/example.com.access.log;
  error_log /var/log/nginx/example.com.error.log;

  location / {
    try_files $uri $uri/ =404;
  }
}

Save and exit.

33.11 Test and Reload Nginx

Check the Nginx config for syntax errors:

sudo nginx -t

If the test passes, reload Nginx:

sudo systemctl reload nginx

If you prefer a full restart:

sudo systemctl restart nginx

33.12 Point Your Domain to the Droplet

In your DNS provider, create these records:

Type Name Value
A @ YOUR_DROPLET_IPV4
A www YOUR_DROPLET_IPV4
AAAA @ YOUR_DROPLET_IPV6, optional
AAAA www YOUR_DROPLET_IPV6, optional

Then test:

curl -I http://example.com
curl -I http://www.example.com

33.13 Install HTTPS with Certbot

Install Certbot and the Nginx plugin:

sudo dnf install -y certbot python3-certbot-nginx

Request and install a certificate:

sudo certbot --nginx -d example.com -d www.example.com

Follow the prompts.

After Certbot finishes, test HTTPS:

curl -I https://example.com

Check the automatic renewal process:

sudo certbot renew --dry-run

33.14 Useful Nginx Commands

Check status:

sudo systemctl status nginx --no-pager

Start Nginx:

sudo systemctl start nginx

Stop Nginx:

sudo systemctl stop nginx

Restart Nginx:

sudo systemctl restart nginx

Reload Nginx without fully restarting:

sudo systemctl reload nginx

Test the Nginx config:

sudo nginx -t

View the installed Nginx version:

nginx -v

View the full active Nginx configuration:

sudo nginx -T

33.15 Useful Log Commands

View the default access log:

sudo tail -f /var/log/nginx/access.log

View the default error log:

sudo tail -f /var/log/nginx/error.log

View logs for the custom site:

sudo tail -f /var/log/nginx/example.com.access.log
sudo tail -f /var/log/nginx/example.com.error.log

View Nginx logs through systemd:

sudo journalctl -u nginx -f

Show recent Nginx service logs:

sudo journalctl -u nginx -n 100 --no-pager

33.16 Basic Reverse Proxy Example

Use this if Nginx should proxy traffic to a local Node.js, Next.js, Strapi, Express, Fastify, Astro, or other app running on the Droplet.

Example app port: 3000

Create a config:

sudo nano /etc/nginx/conf.d/app.example.com.conf

Add this:

server {
  listen 80;
  listen [::]:80;

  server_name app.example.com;

  access_log /var/log/nginx/app.example.com.access.log;
  error_log /var/log/nginx/app.example.com.error.log;

  location / {
    proxy_pass http://127.0.0.1:3000;

    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

Test and reload:

sudo nginx -t
sudo systemctl reload nginx

If SELinux blocks the reverse proxy connection, allow Nginx to make network connections:

sudo setsebool -P httpd_can_network_connect 1

33.17 Remove or Disable the Default Welcome Page

Fedora's default Nginx config may still serve the default welcome page when visiting the Droplet by IP address.

Check the full Nginx config:

sudo nginx -T | less

If needed, create a catch-all default server:

sudo nano /etc/nginx/conf.d/00-default.conf

Add:

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  server_name _;

  return 444;
}

Then test and reload:

sudo nginx -t
sudo systemctl reload nginx

33.18 Quick Troubleshooting Checklist

Nginx is not running

sudo systemctl status nginx --no-pager
sudo journalctl -u nginx -n 100 --no-pager

Nginx config has an error

sudo nginx -t

Firewall is blocking traffic

sudo firewall-cmd --list-all
sudo firewall-cmd --query-service=http
sudo firewall-cmd --query-service=https

Port 80 or 443 is not listening

sudo ss -tulpn | grep -E ':80|:443'

DNS is not pointing to the Droplet

dig example.com
dig www.example.com

If dig is not installed:

sudo dnf install -y bind-utils

SELinux may be blocking file access

Check recent SELinux denials:

sudo ausearch -m AVC,USER_AVC -ts recent

If ausearch is missing:

sudo dnf install -y audit

Restore contexts on the web root:

sudo restorecon -Rv /var/www/example.com

SELinux may be blocking reverse proxy connections

For reverse proxy apps, allow outbound network connections from Nginx:

sudo setsebool -P httpd_can_network_connect 1

DigitalOcean Cloud Firewall is blocking traffic

In the DigitalOcean dashboard, check that inbound TCP traffic is allowed on:

  • Port 22 for SSH
  • Port 80 for HTTP
  • Port 443 for HTTPS

Remember that DigitalOcean Cloud Firewall rules and Fedora firewall rules are separate. Both need to allow the traffic.

33.19 Recommended File Layout

A simple layout for one domain:

/var/www/example.com/html/index.html
/etc/nginx/conf.d/example.com.conf
/var/log/nginx/example.com.access.log
/var/log/nginx/example.com.error.log

A simple layout for a reverse proxy app:

/etc/nginx/conf.d/app.example.com.conf
/var/log/nginx/app.example.com.access.log
/var/log/nginx/app.example.com.error.log

33.20 Nginx and DigitalOcean References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment