From 89cad4365a8438c3a4a20f3a3e1b5e55639dc8ee Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:50:12 +0200 Subject: [PATCH] Add Shlink Web Client install and update support Add optional Shlink Web Client installation and update workflow, switch init to use shlink-installer, and expose the web UI on port 3000. Changes include: use vendor/bin/shlink-installer init (sourcing /opt/shlink/.env) instead of direct db:migrate/create; create data directories (cache, locks, logs, proxies, temp-geolite); add interactive prompt to install the web client, fetch and deploy shlink-web-client GitHub releases, generate /opt/shlink-web-client/servers.json with the initial API key, and configure an nginx site serving the client on port 3000. The ct update script now also checks for and updates the web client release. Update metadata (json/shlink.json) to set interface_port to 3000 and add an info note about API (8080) vs Web Client (3000). Also print the 3000 URL on completion. --- ct/shlink.sh | 13 ++++++++- install/shlink-install.sh | 60 +++++++++++++++++++++++++++++++++++++-- json/shlink.json | 6 +++- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/ct/shlink.sh b/ct/shlink.sh index 89604399..5d3186b1 100644 --- a/ct/shlink.sh +++ b/ct/shlink.sh @@ -52,7 +52,10 @@ function update_script() { cd /opt/shlink $STD php ./vendor/bin/rr get --no-interaction --location bin/ chmod +x bin/rr - $STD php bin/cli db:migrate --no-interaction + set -a + source /opt/shlink/.env + set +a + $STD php vendor/bin/shlink-installer init --no-interaction --clear-db-cache --skip-download-geolite msg_ok "Updated Application" msg_info "Starting Service" @@ -60,6 +63,13 @@ function update_script() { msg_ok "Started Service" msg_ok "Updated successfully!" fi + + if [[ -d /opt/shlink-web-client ]]; then + if check_for_gh_release "shlink-web-client" "shlinkio/shlink-web-client"; then + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shlink-web-client" "shlinkio/shlink-web-client" "prebuild" "latest" "/opt/shlink-web-client" "shlink-web-client_*_dist.zip" + msg_ok "Updated Web Client" + fi + fi exit } @@ -71,3 +81,4 @@ msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW} Access it using the following URL:${CL}" echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL} diff --git a/install/shlink-install.sh b/install/shlink-install.sh index 19dd992a..c5605dfd 100644 --- a/install/shlink-install.sh +++ b/install/shlink-install.sh @@ -23,6 +23,7 @@ msg_info "Setting up Application" cd /opt/shlink $STD php ./vendor/bin/rr get --no-interaction --location bin/ chmod +x bin/rr +mkdir -p data/cache data/locks data/log data/proxies data/temp-geolite chmod -R 775 data cat </opt/shlink/.env DEFAULT_DOMAIN=${LOCAL_IP}:8080 @@ -34,8 +35,10 @@ DB_PASSWORD=${MARIADB_DB_PASS} DB_HOST=127.0.0.1 DB_PORT=3306 EOF -$STD php bin/cli db:create --no-interaction -$STD php bin/cli db:migrate --no-interaction +set -a +source /opt/shlink/.env +set +a +$STD php vendor/bin/shlink-installer init --no-interaction --clear-db-cache --skip-download-geolite API_OUTPUT=$(php bin/cli api-key:generate --name=default 2>&1) INITIAL_API_KEY=$(echo "$API_OUTPUT" | sed -n 's/.*Generated API key: "\([^"]*\)".*/\1/p') if [[ -n "$INITIAL_API_KEY" ]]; then @@ -43,6 +46,59 @@ if [[ -n "$INITIAL_API_KEY" ]]; then fi msg_ok "Set up Application" +if prompt_confirm "Install Shlink Web Client?" "y" 60; then + msg_info "Installing Dependencies" + $STD apt install -y nginx + msg_ok "Installed Dependencies" + + fetch_and_deploy_gh_release "shlink-web-client" "shlinkio/shlink-web-client" "prebuild" "latest" "/opt/shlink-web-client" "shlink-web-client_*_dist.zip" + + msg_info "Setting up Web Client" + cat </opt/shlink-web-client/servers.json +[ + { + "name": "Shlink", + "url": "http://${LOCAL_IP}:8080", + "apiKey": "${INITIAL_API_KEY}" + } +] +EOF + cat <<'EOF' >/etc/nginx/sites-available/shlink-web-client +server { + listen 3000 default_server; + charset utf-8; + root /opt/shlink-web-client; + index index.html; + + location ~* \.(?:manifest|appcache|html?|xml|json)$ { + expires -1; + } + + location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { + expires 1M; + add_header Cache-Control "public"; + } + + location ~* \.(?:css|js)$ { + expires 1y; + add_header Cache-Control "public"; + } + + location = /servers.json { + try_files /servers.json /conf.d/servers.json; + } + + location / { + try_files $uri $uri/ /index.html$is_args$args; + } +} +EOF + ln -sf /etc/nginx/sites-available/shlink-web-client /etc/nginx/sites-enabled/shlink-web-client + rm -f /etc/nginx/sites-enabled/default + $STD systemctl reload nginx + msg_ok "Set up Web Client" +fi + msg_info "Creating Service" cat </etc/systemd/system/shlink.service [Unit] diff --git a/json/shlink.json b/json/shlink.json index 9256a40b..6c9384d3 100644 --- a/json/shlink.json +++ b/json/shlink.json @@ -8,7 +8,7 @@ "type": "ct", "updateable": true, "privileged": false, - "interface_port": 8080, + "interface_port": 3000, "documentation": "https://shlink.io/documentation/", "website": "https://shlink.io/", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/shlink.webp", @@ -39,6 +39,10 @@ { "text": "Configure your short domain by editing DEFAULT_DOMAIN in /opt/shlink/.env and restarting the service.", "type": "info" + }, + { + "text": "Shlink API runs on port 8080, the Web Client (if installed) on port 3000.", + "type": "info" } ] } \ No newline at end of file