Skip to content

Instantly share code, notes, and snippets.

@zany130
Last active August 18, 2025 19:21
Show Gist options
  • Save zany130/4bf4ca4d126f7c6112166e281aeef327 to your computer and use it in GitHub Desktop.
Save zany130/4bf4ca4d126f7c6112166e281aeef327 to your computer and use it in GitHub Desktop.
Install portmaster to home directory
#!/usr/bin/env bash
set -e # Exit on error
if [ "$EUID" -eq 0 ]; then
echo "To ensure correct permissions, this script must be run as user."
exit 1
fi
# Paths to use for portmaster install Must not include trailing slash
data_dir="/home/$USER/.local/lib/portmaster"
log_dir="/home/$USER/.local/lib/portmaster/logs"
bin_dir="/home/$USER/.local/bin/portmaster"
systemd_dir="/home/$USER/.config/systemd/user"
autostart_dir="/home/$USER/.config/autostart"
exports_dir="/home/$USER/.local"
# ===================================
# STEP 1: Install Portmaster
# (install all necessary files)
# ===================================
# Create directory for binaries
mkdir -p "${bin_dir}"
cd "${bin_dir}"
# Download Portmaster UpdateManager utility
echo "[+] Downloading Portmaster UpdateManager..."
wget https://updates.safing.io/latest/linux_amd64/updatemgr/updatemgr
chmod a+x updatemgr
# Download latest binaries
echo "[+] Downloading Portmaster binaries..."
./updatemgr download https://updates.safing.io/stable.v3.json "${bin_dir}"
chmod a+x "${bin_dir}/portmaster" # Ensure binary is executable
chmod a+x "${bin_dir}/portmaster-core" # Ensure binary is executable
# Download latest data files
echo "[+] Downloading Portmaster data files..."
mkdir -p "${data_dir}"/intel
./updatemgr download https://updates.safing.io/intel.v3.json "${data_dir}/intel"
# (Optional)
# If the SELinux module is enabled, set correct SELinux context for the Portmaster core binary.
# This ensures the binary can be executed properly under SELinux policies, avoiding permission issues.
if command -v semanage >/dev/null 2>&1; then
echo "[ ] Fixing SELinux permissions"
semanage fcontext -a -t bin_t -s system_u "$(realpath "${bin_dir}")" || :
restorecon -R "${bin_dir}/portmaster-core" 2>/dev/null >&2 || :1
fi
# Clean up
rm -f "${bin_dir}/updatemgr"
# Done
echo "[i] At this point, Portmaster is installed."
echo " You can start manually running the Portmaster daemon with:"
echo " ${bin_dir}/portmaster-core --log-stdout"
echo " To start User Interface, run:"
echo " ${bin_dir}/portmaster"
# ===================================
# STEP 2: Register Portmaster service
# (for systemd-based systems)
# ===================================
mkdir -p "${exports_dir}/units"
echo "[+] Registering Portmaster service"
cat <<EOF > "${systemd_dir}/portmaster.service"
[Unit]
Description=Portmaster by Safing
Documentation=https://safing.io
Documentation=https://docs.safing.io
Before=nss-lookup.target network.target shutdown.target
After=systemd-networkd.service
Conflicts=shutdown.target
Conflicts=firewalld.service
Wants=nss-lookup.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10
RestartPreventExitStatus=24
LockPersonality=yes
MemoryDenyWriteExecute=yes
MemoryLow=2G
NoNewPrivileges=yes
PrivateTmp=yes
PIDFile=${data_dir}/core-lock.pid
Environment=LOGLEVEL=info
Environment=PORTMASTER_ARGS=
EnvironmentFile=-/etc/default/portmaster
ProtectSystem=true
ReadWritePaths=${data_dir}
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictNamespaces=yes
ProtectHome=read-only
ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
PrivateDevices=yes
AmbientCapabilities=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon
CapabilityBoundingSet=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon
StateDirectory=portmaster
WorkingDirectory=${data_dir}
ExecStart=${bin_dir}/portmaster-core --log-dir=${log_dir} --bin-dir ${bin_dir} --data-dir ${data_dir} -- $PORTMASTER_ARGS
ExecStopPost=-${bin_dir}/portmaster-core -recover-iptables
[Install]
WantedBy=multi-user.target
EOF
systemctl --user daemon-reload
systemctl --user enable portmaster
ln -s "${systemd_dir}/portmaster.service" "${exports_dir}/units/portmaster.service"
# ===================================
# STEP 3: Register Portmaster UI
# (for desktop environments)
# ===================================
# Install Portmaster UI start script
echo "[+] Installing Portmaster UI start script"
cat <<EOF > "${bin_dir}/portmaster-ui-start.sh"
#!/bin/sh
WEBKIT_DISABLE_COMPOSITING_MODE=1 ${bin_dir}/portmaster "$@"
EOF
chmod a+x "${bin_dir}/portmaster-ui-start.sh"
# Register Portmaster UI in the system
echo "[+] Registering Portmaster UI .desktop file"
mkdir -p "${exports_dir}/share/applications"
cat <<EOF > "${exports_dir}/share/applications/portmaster.desktop"
[Desktop Entry]
Name=Portmaster
GenericName=Application Firewall
Exec=${bin_dir}/portmaster-ui-start.sh --with-prompts --with-notifications
Icon=portmaster
StartupWMClass=portmaster
Terminal=false
Type=Application
Categories=System
EOF
# Register Portmaster UI to automatically start on login
echo "[+] Registering Portmaster UI to start on login"
mkdir -p "${autostart_dir}"
cat <<EOF > "${autostart_dir}/portmaster-autostart.desktop"
[Desktop Entry]
Name=Portmaster
GenericName=Application Firewall Notifier
Exec=${bin_dir}/portmaster-ui-start.sh --with-prompts --with-notifications --background
Icon=portmaster
Terminal=false
Type=Application
Categories=System
NoDisplay=true
EOF
# Register Portmaster icon
echo "[+] Registering Portmaster icon"
wget https://raw.githubusercontent.com/safing/portmaster-packaging/master/linux/portmaster_logo.png -O "${exports_dir}/share/icons/portmaster.png"
# Adding install_location to XDG_DATA_DIRS to show desktop entries (applies after next login)"
#echo "-> Adding '${exports_dir}' to \$XDG_DATA_DIRS to show desktop entries (applies after next login)"
#echo "XDG_DATA_DIRS=${exports_dir}/share:\$XDG_DATA_DIRS" >/etc/profile.d/zzz-portmaster-to-xdg-data-dirs.sh # We prepend 'zzz' since profile.d scripts aren't numbered on Fedora, and we want to run after any other scripts that modify XDG_DATA_DIRS.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment