Skip to content

Instantly share code, notes, and snippets.

@lawrenceching
Last active December 30, 2025 21:07
Show Gist options
  • Select an option

  • Save lawrenceching/41244a182307940cc15b45e3c4997346 to your computer and use it in GitHub Desktop.

Select an option

Save lawrenceching/41244a182307940cc15b45e3c4997346 to your computer and use it in GitHub Desktop.
Install frp as systemd service
#!/bin/bash
# Update on 2024/05/29
# 1. use wget to fetch latest frp version when curl was not installed
# 2. Remind users that frp will be run in non-root user
# 3. Add CI
#
# Update on 2024/04/13
# 1. Improved OS compatibility: try wget and then curl for downloading files.
#
# Update on 2024/01/26
# 1. Thanks to GitHub user @aka-Ani, this script now will install latest version of frp:
# https://gist.github.com/lawrenceching/41244a182307940cc15b45e3c4997346?permalink_comment_id=4851742#gistcomment-4851742
# 2. Use .toml conf file as .ini became lagacy
#
# Update on 2023/06/19
# 1. frp no longer provide systemctl service file. This script creates frpc/fprs systemctl service file by itself
# 2. Update frp from 0.33.0 to 0.49.0
# 3. User=nobody is no longer suggested, use DynamicUser=yes instead
# ---
# set platform (latest options as of 2024/01/25), choose one of:
# darwin_amd64
# darwin_arm64
# freebsd_amd64
# linux_amd64
# linux_arm
# linux_arm64
# linux_mips
# linux_mips64le
# linux_mipsle
# linux_riscv64
# windows_amd64
# windows_arm64
platform=linux_amd64
WGET_INSTALLED=$(command -v wget &> /dev/null && echo 'true')
CURL_INSTALLED=$(command -v curl &> /dev/null && echo 'true')
if [[ "$WGET_INSTALLED" != 'true' && "$CURL_INSTALLED" != 'true' ]]; then
echo "Neither wget nor curl is installed" 1>&2
exit 1
fi
# download url can be determined by parsing the json of the releases/latest url.
# each asset has a browser_download_url key, and we want the value where the platform is the one chosen above
if [[ "$WGET_INSTALLED" == 'true' ]]; then
d_url=$(wget -qO- https://api.github.com/repos/fatedier/frp/releases/latest | grep browser_download_url | grep $platform | head -n 1 | cut -d '"' -f 4)
else
d_url=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest | grep browser_download_url | grep $platform | head -n 1 | cut -d '"' -f 4)
fi
echo "Latest version URL: $d_url"
wget -q -P /tmp $d_url || curl -O -L --output-dir /tmp $d_url
DIR=$(basename $d_url .tar.gz)
tar -zxvf /tmp/$DIR.tar.gz -C /tmp
mkdir -p /etc/frp
cp /tmp/$DIR/frpc.toml /etc/frp/frpc.toml
cp /tmp/$DIR/frps.toml /etc/frp/frps.toml
cp /tmp/$DIR/frpc /usr/bin/
cp /tmp/$DIR/frps /usr/bin/
echo '[Unit]
Description=Frp Client Service
After=network.target
[Service]
Type=simple
DynamicUser=yes
Restart=on-failure
RestartSec=5s
ExecStart=/usr/bin/frpc -c /etc/frp/frpc.toml
ExecReload=/usr/bin/frpc reload -c /etc/frp/frpc.toml
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target' > /etc/systemd/system/frpc.service
echo '[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
DynamicUser=yes
Restart=on-failure
RestartSec=5s
ExecStart=/usr/bin/frps -c /etc/frp/frps.toml
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target' > /etc/systemd/system/frps.service
systemctl daemon-reload
systemctl status frpc
systemctl status frps
echo '
frps and frpc are installed.
Modify /etc/frp/frpc.toml or /etc/frp/frps.toml
And then run
systemctl enable frps
systemctl start frps
or
systemctl enable frpc
systemctl start frpc
to launch the services
Remove "DynamicUser=yes" in .toml files if you want frp run in root (which is not suggested for security reason).
'
@iszhi
Copy link
Copy Markdown

iszhi commented Nov 4, 2022

It works pretty well!

@NickLucche
Copy link
Copy Markdown

May want to also grab these *.service files with the latest release (0.48 atm) fatedier/frp#3048 (comment)

@iszhi
Copy link
Copy Markdown

iszhi commented Jun 12, 2023

@NickLucche I think that is possible. Just edit the version of frp.

@lawrenceching
Copy link
Copy Markdown
Author

@NickLucche
Uplifted frp to latest 0.49.0.

And other changes are listed at the top of script.

@aka-Ani
Copy link
Copy Markdown

aka-Ani commented Jan 25, 2024

Thanks for this! just an aside, I changed all references of .ini files to .toml files (I think ini is deprecated as of 0.52.0)

@aka-Ani
Copy link
Copy Markdown

aka-Ani commented Jan 26, 2024

Also for what its worth, the latest version could be determined in-script with something like this at the beginning:

# set platform (latest options as of 2024/01/25), choose one of:
#   darwin_amd64
#   darwin_arm64
#   freebsd_amd64
#   linux_amd64
#   linux_arm
#   linux_arm64
#   linux_mips
#   linux_mips64le
#   linux_mipsle
#   linux_riscv64
#   windows_amd64
#   windows_arm64

platform=linux_amd64

# download url can be determined by parsing the json of the releases/latest url. 
# each asset has a browser_download_url key, and we want the value where the platform is the one chosen above
d_url=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest | grep browser_download_url | grep $platform | head -n 1 | cut -d '"' -f 4)
echo "Latest version URL: $d_url"

# perform the download. using curl instead of wget for simpler macos cross-compatibility
curl -O --output-dir /tmp $d_url

DIR=$(basename $d_url .tar.gz)

<continue rest of the script as before>

@lawrenceching
Copy link
Copy Markdown
Author

@aka-Ani thanks for you contribution!

@aka-Ani
Copy link
Copy Markdown

aka-Ani commented Jan 26, 2024 via email

@ligand-lg
Copy link
Copy Markdown

very helpful! thanks

@kelke
Copy link
Copy Markdown

kelke commented Apr 5, 2024

I actually prefer wget over curl, as debian in my specific environment (lxc in proxmox) has wget preinstalled, but not curl.
So since this cant be used on macOS anyway, I believe wget hat greater compatibility.

@aka-Ani
Copy link
Copy Markdown

aka-Ani commented Apr 5, 2024

I actually prefer wget over curl, as debian in my specific environment (lxc in proxmox) has wget preinstalled, but not curl. So since this cant be used on macOS anyway, I believe wget hat greater compatibility.

I agree!

@lawrenceching
Copy link
Copy Markdown
Author

@kelke @aka-Ani
thanks for your suggestion. I updated script to try wget first and then curl.

@kelke
Copy link
Copy Markdown

kelke commented Apr 17, 2024

By the way, for anyone experiencing problems with binding on ports lower than 1024 in frps.toml:
I needed to remove the line: DynamicUser=yes from the frp-server systemd-config /etc/systemd/system/frps.service, as it seems the service then does not run as root.
Removing the line does run the service as root, so keep that in mind from a security-perspective.
grafik

@agrofx1
Copy link
Copy Markdown

agrofx1 commented Apr 23, 2024

The best systemd services of all! I've tried another services from different tutorials but yours are most reliable

@pnxl
Copy link
Copy Markdown

pnxl commented May 19, 2024

Great script! Btw, you still need to install curl for the command at the beginning, otherwise it wouldn't install frp at all - thought you should know :)

@Blakeinstein
Copy link
Copy Markdown

Blakeinstein commented May 28, 2024

I keep getting frps.service: Failed at step EXEC spawning /usr/bin/frps: Permission denied in my service logs. Running it outside of systemd, using sudo works just fine. Anybody have a clue?

I tried setting permissions, changing owners, etc.

@kelke
Copy link
Copy Markdown

kelke commented May 28, 2024

I keep getting frps.service: Failed at step EXEC spawning /usr/bin/frps: Permission denied in my service logs. Running it outside of systemd, using sudo works just fine. Anybody have a clue?

I tried setting permissions, changing owners, etc.

Did you bind on a port <1024? If so, only root/sudo can do that

@aka-Ani
Copy link
Copy Markdown

aka-Ani commented Jun 13, 2024

Great script! Btw, you still need to install curl for the command at the beginning, otherwise it wouldn't install frp at all - thought you should know :)

@pnxl haha truuue, good catch

@lawrenceching
Copy link
Copy Markdown
Author

Great script! Btw, you still need to install curl for the command at the beginning, otherwise it wouldn't install frp at all - thought you should know :)

silly of me. Orz.
fixed.

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