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.
This guide covers the following applications and tools.
- Terminator terminal
- Zsh
- Oh My Zsh
- Git and Git LFS
- nvm
- Node.js LTS
- AWS CLI v2
- AppImage support with FUSE
- Google Chrome Stable
- Visual Studio Code
- Cursor IDE
- Google Antigravity IDE
- Postman
- Docker Engine
- Docker CLI
- Docker Buildx
- Docker Compose plugin
- Docker Desktop
- NVIDIA Container Toolkit for GPU containers
- RPM Fusion repositories
- NVIDIA proprietary driver through
akmod-nvidia - NVIDIA settings UI
- Vulkan tools
- OpenGL tools
- LM Studio AppImage
- LM Studio applications menu launcher
- Slack
- Steam
- Proton and Steam Play
- GameMode
- MangoHud
- Gamescope
- Brother HL-L2405W printer setup
- CUPS
- Avahi printer discovery
- Cameractrls
- guvcview
- OBS Studio
- Mission Center
- nvtop
- btop
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,MOUNTPOINTSDo not assume /dev/nvme0n1 is the install target. NVMe numbering can change.
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
hostnamectlCheck 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 rebootIf Cinnamon blocks the reboot with a session inhibitor, save your work and run:
sudo systemctl reboot -iYou can inspect blockers with:
systemd-inhibit --listYour 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.
List each disk, partition, filesystem type, label, UUID, model, and current mount point:
lsblk -e7 -o NAME,SIZE,FSTYPE,LABEL,UUID,MODEL,MOUNTPOINTSShow additional filesystem identifiers:
sudo blkidShow filesystems that are currently mounted:
findmnt --realSelect 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_PARTITIONReplace /dev/DEVICE_PARTITION with the real partition path.
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/archiveYou only need to create the mount points you plan to use.
For each partition, run:
sudo blkid -s UUID -s TYPE -o full /dev/DEVICE_PARTITIONExample 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.
Create a timestamped backup before editing:
sudo cp -a /etc/fstab "/etc/fstab.backup.$(date +%Y%m%d-%H%M%S)"
sudoedit /etc/fstabAdd 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 unavailablenoatime: avoid updating file access timestamps on every readx-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 -gThen 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.
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 -aConfirm each mount:
findmnt /mnt/projects
df -hT /mnt/projectsRepeat 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.
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/projectsThis 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.
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"Install Terminator:
sudo dnf install -y terminatorLaunch it:
terminatorOptional: 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.
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 --refreshVerify:
dnf repolist | grep rpmfusionYou should see RPM Fusion free and nonfree repositories.
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 ShellCheckEnable Git LFS:
git lfs installCheck AppImage support packages:
rpm -q fuse fuse-libsFedora'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 trueVerify:
git --version
git lfs version
git config --global --listSet 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"
fiAdd 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 --versionInstall nvm into your Zsh profile:
curl -fsSL -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | PROFILE="$HOME/.zshrc" bashOpen 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 --versionEnable Corepack for pnpm and Yarn support:
corepack enableOptional: install the current Node release too:
nvm install nodeUseful commands:
nvm ls
nvm current
nvm install --lts
nvm use --ltsInstall 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 --versionConfigure with SSO:
aws configure ssoOr configure classic access keys:
aws configureVerify credentials:
aws sts get-caller-identityUse RPM Fusion packages. Do not use NVIDIA's .run installer unless you have a very specific reason.
mokutil --sb-stateIf 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.
Install signing tools:
sudo dnf install -y akmods kmodtool mokutil opensslGenerate the akmods signing key if it does not exist:
sudo test -f /etc/pki/akmods/certs/public_key.der || sudo kmodgenca -aImport the key:
sudo mokutil --import /etc/pki/akmods/certs/public_key.derCreate a temporary password when prompted. Then reboot:
sudo rebootOn the blue MOK screen:
- Choose
Enroll MOK - Choose
Continue - Choose
Yes - Enter the password you created
- Reboot
After booting back into Fedora, verify:
mokutil --test-key /etc/pki/akmods/certs/public_key.dersudo dnf install -y akmod-nvidia xorg-x11-drv-nvidia-cuda nvidia-settingsMark the akmod package as user-installed so it is not accidentally removed later:
sudo dnf mark user akmod-nvidiaBuild the module and regenerate initramfs:
sudo akmods --force
sudo dracut --forceIf 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 --forceIf 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 rebootThen build again after reboot:
sudo akmods --force
sudo dracut --force
sudo rebootmodinfo -F version nvidia
nvidia-smi
lsmod | grep '^nvidia'
glxinfo -B | grep -E 'OpenGL vendor|OpenGL renderer'
vulkaninfo --summary | grep -Ei 'deviceName|driverName' || trueExpected result:
nvidia-smishows the NVIDIA GeForce RTX 4060lsmodshowsnvidia,nvidia_modeset,nvidia_drm, and oftennvidia_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.serviceYou 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.
This uses Docker's official Fedora repository.
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
donesudo 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 --refreshVerify:
dnf repolist | grep -i dockersudo dnf install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-pluginWhen 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-pagerSecurity 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 dockerVerify:
groups
docker run hello-world
docker compose versionmkdir -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"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.repoInstall the toolkit:
sudo dnf install -y nvidia-container-toolkitConfigure Docker:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart dockerTest GPU access in a container:
docker run --rm --gpus all ubuntu nvidia-smiIf Docker permission fails:
sudo docker run --rm --gpus all ubuntu nvidia-smiDocker 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.
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 gnupg2Check KVM:
lsmod | grep kvmFor the Ryzen 9 7900X, you should see kvm_amd. If not:
sudo modprobe kvm
sudo modprobe kvm_amdAdd yourself to the kvm group:
sudo usermod -aG kvm "$USER"Reboot or log out and back in:
sudo systemctl reboot -iVerify:
groups
ls -l /dev/kvmmkdir -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.rpmStart from Terminator:
systemctl --user start docker-desktopOr 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-desktopVerify contexts:
docker context ls
docker context showSwitch to Docker Desktop:
docker context use desktop-linux
docker run hello-worldSwitch back to local Docker Engine:
docker context use defaultAdd 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"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.
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.rpmVerify the package, executable, and repository:
rpm -q google-chrome-stable
google-chrome-stable --version
dnf repolist | grep -i google-chromeLaunch Chrome:
google-chrome-stableChrome should also appear in the Cinnamon applications menu as Google Chrome.
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-browserIf 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.rpmIf Chrome's repository exists but is disabled, inspect it:
sudo cat /etc/yum.repos.d/google-chrome.repo
dnf repolist --all | grep -i google-chromeAdd 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 codeVerify:
code --versionOptional 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-actionsIf your system already has the Cursor repository configured:
sudo dnf makecache
sudo dnf install -y cursorIf Fedora cannot find the package, open the download page:
xdg-open https://cursor.com/downloadDownload 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 || trueAdd 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 antigravityNote: 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 || truePreferred path: install the official Linux RPM from Slack's download page.
Open the page:
xdg-open https://slack.com/downloads/linuxDownload 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 slackFlatpak 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.SlackUse either RPM Slack or Flatpak Slack. Do not install both unless you intentionally want two copies.
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/postmanTest:
postmanCreate 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 || trueOptional 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.
LM Studio for Linux is available as an AppImage. Keep it in ~/Applications and create a .desktop launcher.
sudo dnf install -y fuse fuse-libsOpen the official download page:
xdg-open "https://lmstudio.ai/download?os=linux"Download the Linux x64 AppImage.
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"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 || trueSearch the Cinnamon applications menu for:
LM Studio
If it does not appear immediately, log out and log back in.
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:
lmstudioFor 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 || trueReplace 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-libsIf it still fails, try extracting it:
cd "$HOME/Applications"
./MyApp.AppImage --appimage-extract
./squashfs-root/AppRunsudo dnf install -y steamIf RPM Fusion picks a bad mirror and times out, use the troubleshooting section near the end of this guide.
Launch Steam:
steamIf 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.SteamIn Steam:
Steam > Settings > Compatibility
Enable:
Enable Steam Play for supported titles
Enable Steam Play for all other titles
sudo dnf install -y gamemode mangohud gamescopePer-game launch options:
gamemoderun %command%
With MangoHud:
mangohud gamemoderun %command%
Verify GameMode while a game is running:
gamemoded -sMission 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.MissionCenterLaunch:
flatpak run io.missioncenter.MissionCenterOr search the applications menu for:
Mission Center
sudo dnf install -y nvtop btopUse:
nvtop
btopRecommended pattern:
Mission Center = daily GUI monitor
nvtop = NVIDIA GPU monitor in the terminal
btop = CPU, RAM, disks, network, and processes in the terminal
Your EMEET camera uses the standard Linux uvcvideo stack, so V4L2 camera tools are the right starting point.
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub hu.irl.cameractrlsLaunch:
flatpak run hu.irl.cameractrlsIn 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 || trueThen 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 || truesudo dnf install -y v4l-utilsList cameras:
v4l2-ctl --list-devicesList controls:
v4l2-ctl --list-ctrlsInspect a camera:
v4l2-ctl -d /dev/video0 --allExample 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=128Exact control names depend on the webcam.
sudo dnf install -y guvcview obs-studioUse:
guvcview
obsRecommended 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
Try driverless AirPrint/IPP first. Brother's Linux page for this class of printer recommends AirPrint when available.
sudo dnf install -y cups cups-client cups-filters system-config-printer avahi nss-mdns avahi-toolsEnable services:
sudo systemctl enable --now cups
sudo systemctl enable --now avahi-daemonFor Wi-Fi, connect the Brother HL-L2405W to the same network as your Fedora machine.
For USB, plug the printer directly into the machine.
lpinfo -v | grep -i brother || true
driverless || true
avahi-browse -rt _ipp._tcpsystem-config-printerThen:
- Click
Add - Select the Brother printer if it appears
- Prefer a driverless, AirPrint, or IPP option
- Name it
Brother_HL_L2405W - Print a test page
List devices:
lpinfo -vIf 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_L2405WExample 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_L2405WTest:
lpstat -p -d
echo "Brother HL-L2405W Fedora test page" | lp -d Brother_HL_L2405WOnly 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-* HLL2405WWhen prompted for DeviceURI:
- USB: choose
N - Wi-Fi or Ethernet: choose
Y, then specify the printer IP address
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 || trueThen 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.SlackUse 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.pemIf /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 extractVerify:
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.xmlThen refresh DNF:
sudo dnf clean all
sudo dnf makecache --refreshDo not use this command on Fedora if it errors:
sudo update-ca-trust force-enableOn your Fedora install, force-enable was not a valid update-ca-trust command. sudo update-ca-trust extract is the command you need.
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 --refreshRetry the install:
sudo dnf \
--refresh \
--setopt=timeout=180 \
--setopt=retries=20 \
--setopt=minrate=1 \
install -y steamFor 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=1Run 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.shUpdate Fedora packages, including Google Chrome from its configured repository:
sudo dnf upgrade --refresh -yUpdate only Google Chrome when needed:
sudo dnf upgrade --refresh -y google-chrome-stable
google-chrome-stable --versionUpdate Oh My Zsh:
omz updateUpdate 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 --versionUpdate 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/postmanUpdate LM Studio AppImage:
- Download the newest Linux x64 AppImage from LM Studio.
- 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.rpmAfter Fedora kernel updates, the NVIDIA module should rebuild through akmods. If the NVIDIA driver fails after reboot:
sudo akmods --force
sudo dracut --force
sudo rebootUse this order on a fresh Fedora 44 Cinnamon install:
- Install Fedora 44 Cinnamon and update the system
- Inventory the internal disks and configure UUID-based automatic mounts
- Install Terminator
- Enable RPM Fusion
- Install base developer packages
- Configure Git
- Install Zsh and Oh My Zsh
- Install nvm and Node.js LTS
- Install AWS CLI v2
- Install NVIDIA drivers and reboot
- Install Docker Engine and Compose
- Install NVIDIA Container Toolkit if you need GPU containers
- Install Docker Desktop if you want the GUI
- Install Google Chrome
- Install VS Code, Cursor, Antigravity, and Postman
- Install Slack
- Install LM Studio AppImage and launcher
- Install Steam, Proton support, GameMode, MangoHud, and Gamescope
- Install Mission Center, nvtop, and btop
- Install camera tools
- Set up the Brother printer
- Run the final verification script
- Fedora Cinnamon Spin: https://fedoraproject.org/spins/cinnamon/download/
- Fedora release notes: https://docs.fedoraproject.org/en-US/fedora/latest/release-notes/
- Fedora boot media docs: https://docs.fedoraproject.org/en-US/fedora/latest/preparing-boot-media/
- Fedora image verification: https://alt.fedoraproject.org/en/verify.html
- Fedora persistent storage identifiers: https://docs.fedoraproject.org/en-US/quick-docs/persistent-identifiers-for-storage-devices/
- RPM Fusion setup: https://docs.fedoraproject.org/en-US/quick-docs/rpmfusion-setup/
- RPM Fusion NVIDIA guide: https://rpmfusion.org/Howto/NVIDIA
- Fedora NVIDIA driver notes: https://docs.fedoraproject.org/en-US/gaming/drivers/
- Fedora MOK enrollment: https://docs.fedoraproject.org/en-US/quick-docs/mok-enrollment/
- Git Linux install docs: https://git-scm.com/install/linux
- Oh My Zsh installer: https://install.ohmyz.sh/
- nvm GitHub: https://github.com/nvm-sh/nvm
- AWS CLI v2 install docs: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- Docker Engine on Fedora: https://docs.docker.com/engine/install/fedora/
- Docker Desktop on Fedora: https://docs.docker.com/desktop/setup/install/linux/fedora/
- Docker Desktop on Linux: https://docs.docker.com/desktop/setup/install/linux/
- NVIDIA Container Toolkit: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
- Docker GPU access: https://docs.docker.com/engine/containers/gpu/
- Google Chrome Linux setup: https://support.google.com/chrome/a/answer/9025903
- Google Chrome Linux RPM download guidance: https://support.google.com/chrome/a/answer/9025926
- VS Code Linux install docs: https://code.visualstudio.com/docs/setup/linux
- Cursor download: https://cursor.com/download
- Google Antigravity Linux install: https://antigravity.google/download/linux
- Slack Linux download: https://slack.com/downloads/linux
- Postman download: https://www.postman.com/downloads/
- LM Studio download: https://lmstudio.ai/download?os=linux
- AppImage FUSE troubleshooting: https://docs.appimage.org/user-guide/troubleshooting/fuse.html
- Steam on Flathub: https://flathub.org/en/apps/com.valvesoftware.Steam
- GameMode: https://feralinteractive.github.io/gamemode/
- Mission Center on Flathub: https://flathub.org/en/apps/io.missioncenter.MissionCenter
- Cameractrls on Flathub: https://flathub.org/en/apps/hu.irl.cameractrls
- Fedora v4l-utils package: https://packages.fedoraproject.org/pkgs/v4l-utils/v4l-utils/
- Fedora guvcview package: https://packages.fedoraproject.org/pkgs/guvcview/guvcview/
- Fedora OBS Studio package: https://packages.fedoraproject.org/pkgs/obs-studio/
- Brother HL-L2405W support: https://support.brother.com/g/b/downloadtop.aspx?c=us&lang=en&prod=hll2405w_us
- CUPS administration: https://www.cups.org/doc/admin.html
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
Use the IP address from your DigitalOcean Droplet dashboard.
ssh root@YOUR_DROPLET_IPOr, if you created a sudo user:
ssh cesar@YOUR_DROPLET_IPBefore installing Nginx, update the system packages.
sudo dnf upgrade --refresh -yIf the update installs a new kernel or a large number of system packages, reboot before continuing.
sudo rebootAfter the Droplet comes back online, reconnect:
ssh root@YOUR_DROPLET_IPOr:
ssh cesar@YOUR_DROPLET_IPInstall Nginx from Fedora's package repositories.
sudo dnf install -y nginxConfirm that Nginx installed correctly:
nginx -v
rpm -q nginxEnable Nginx so it starts automatically on boot:
sudo systemctl enable nginxStart Nginx now:
sudo systemctl start nginxOr enable and start it in one command:
sudo systemctl enable --now nginxCheck the service status:
sudo systemctl status nginx --no-pagerYou should see something like:
Active: active (running)
Fedora commonly uses firewalld. If your Droplet uses firewalld, allow HTTP and HTTPS traffic.
Check whether firewalld is running:
sudo systemctl status firewalld --no-pagerIf it is not installed or not running, install and enable it:
sudo dnf install -y firewalld
sudo systemctl enable --now firewalldAllow HTTP and HTTPS:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reloadVerify the rules:
sudo firewall-cmd --query-service=http
sudo firewall-cmd --query-service=httpsBoth should return:
yes
You can also list the active firewall configuration:
sudo firewall-cmd --list-allDigitalOcean 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.
From your local machine, visit:
http://YOUR_DROPLET_IP
Or test with curl:
curl -I http://YOUR_DROPLET_IPA working response should look similar to:
HTTP/1.1 200 OK
Server: nginx
Replace example.com with your real domain.
sudo mkdir -p /var/www/example.com/htmlCreate 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>
HTMLSet ownership:
sudo chown -R nginx:nginx /var/www/example.comSet reasonable permissions:
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;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-utilsAdd the correct SELinux context:
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.comFedora'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.confAdd 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.
Check the Nginx config for syntax errors:
sudo nginx -tIf the test passes, reload Nginx:
sudo systemctl reload nginxIf you prefer a full restart:
sudo systemctl restart nginxIn 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.comInstall Certbot and the Nginx plugin:
sudo dnf install -y certbot python3-certbot-nginxRequest and install a certificate:
sudo certbot --nginx -d example.com -d www.example.comFollow the prompts.
After Certbot finishes, test HTTPS:
curl -I https://example.comCheck the automatic renewal process:
sudo certbot renew --dry-runCheck status:
sudo systemctl status nginx --no-pagerStart Nginx:
sudo systemctl start nginxStop Nginx:
sudo systemctl stop nginxRestart Nginx:
sudo systemctl restart nginxReload Nginx without fully restarting:
sudo systemctl reload nginxTest the Nginx config:
sudo nginx -tView the installed Nginx version:
nginx -vView the full active Nginx configuration:
sudo nginx -TView the default access log:
sudo tail -f /var/log/nginx/access.logView the default error log:
sudo tail -f /var/log/nginx/error.logView logs for the custom site:
sudo tail -f /var/log/nginx/example.com.access.log
sudo tail -f /var/log/nginx/example.com.error.logView Nginx logs through systemd:
sudo journalctl -u nginx -fShow recent Nginx service logs:
sudo journalctl -u nginx -n 100 --no-pagerUse 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.confAdd 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 nginxIf SELinux blocks the reverse proxy connection, allow Nginx to make network connections:
sudo setsebool -P httpd_can_network_connect 1Fedora'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 | lessIf needed, create a catch-all default server:
sudo nano /etc/nginx/conf.d/00-default.confAdd:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}Then test and reload:
sudo nginx -t
sudo systemctl reload nginxsudo systemctl status nginx --no-pager
sudo journalctl -u nginx -n 100 --no-pagersudo nginx -tsudo firewall-cmd --list-all
sudo firewall-cmd --query-service=http
sudo firewall-cmd --query-service=httpssudo ss -tulpn | grep -E ':80|:443'dig example.com
dig www.example.comIf dig is not installed:
sudo dnf install -y bind-utilsCheck recent SELinux denials:
sudo ausearch -m AVC,USER_AVC -ts recentIf ausearch is missing:
sudo dnf install -y auditRestore contexts on the web root:
sudo restorecon -Rv /var/www/example.comFor reverse proxy apps, allow outbound network connections from Nginx:
sudo setsebool -P httpd_can_network_connect 1In the DigitalOcean dashboard, check that inbound TCP traffic is allowed on:
- Port
22for SSH - Port
80for HTTP - Port
443for HTTPS
Remember that DigitalOcean Cloud Firewall rules and Fedora firewall rules are separate. Both need to allow the traffic.
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
- Fedora Nginx package notes: https://fedoraproject.org/wiki/Nginx
- Firewalld documentation: https://firewalld.org/documentation/howto/open-a-port-or-service.html
- DigitalOcean Cloud Firewall rules: https://docs.digitalocean.com/products/networking/firewalls/how-to/configure-rules/
- Fedora Certbot Nginx package: https://packages.fedoraproject.org/pkgs/certbot/python3-certbot-nginx/