2025年12月15日 星期一

SSH 連線時自訂 PS1 提示符 (Ubuntu為例)

SSH 連線時自訂 PS1 提示符 (Ubuntu為例)

以 Ubuntu 預設彩色提示符為例



方式一:臨時一次性使用(連線後手動執行)

連線進去後,直接在終端機貼上執行:

export PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

說明:

  • 只對當前 session 有效,登出後就消失
  • 不需要任何設定檔修改
  • 適合臨時想換個提示符樣式試試看



方式二:修改遠端伺服器設定

在遠端伺服器的 ~/.bashrc 加入:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

優點:

  • 不影響 scp/rsync 等檔案傳輸功能
  • 所有連線方式都自動套用
  • 不用記複雜的命令
  • 最簡單、最推薦的做法



方式三:連線時指定命令(命令列參數)

每次連線時加上參數:

ssh myserver -t 'export PS1="${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "; exec bash'

說明:

  • -t — 等同於 RequestTTY yes,強制分配 TTY
  • 單引號包住整個命令,避免本地 shell 先展開變數
  • 適合偶爾需要或寫成別名使用



方式四:寫在 SSH Config 中(本地端設定)

在本地的 ~/.ssh/config 中設定:

Host myserver
    HostName example.com
    User ubuntu
    RequestTTY yes
    RemoteCommand bash -c 'export PS1="${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "; exec bash'

說明:

  • RequestTTY yes — 強制分配終端,否則 RemoteCommand 無法正常互動
  • RemoteCommand — 連線後自動執行的命令,用 exec bash 確保留在互動式 shell
  • 連線方式:直接 ssh myserver

注意事項:

  • 使用 RemoteCommand 後,scprsync 等檔案傳輸會失效(因為它會執行指定命令而非預設 shell)
  • 如果需要傳檔案,要另外建一個不帶 RemoteCommand 的 Host 設定




補充:PS1 提示符格式說明

對照格式

\[\033[01;32m\]  → 亮綠色開始
\u              → 使用者名稱
@               → @ 符號
\h              → 主機名稱
\[\033[00m\]    → 重設顏色
:               → : 符號
\[\033[01;34m\] → 亮藍色開始
\w              → 當前完整路徑
\[\033[00m\]    → 重設顏色
\$              → 一般用戶顯示 $,root 顯示 #



2025年12月4日 星期四

自動初始化 Git 倉庫一個空 README.md 當作起點的腳本

自動初始化 Git 倉庫一個空 README.md 當作起點的腳本

這不是必要的,只是我通常習慣第一點用空 README.md 來當作起始,寫個腳本之後要複製比較容易

# 自動初始化Git倉庫腳本
function Initialize-GitRepository {
    [CmdletBinding()]
    [Alias("igr")]
    param(
        [Parameter(Position = 0)]
        [string]$Path = ".",

        [Parameter()]
        [string]$ReadmeFileName = "README.md",

        [Parameter()]
        [string]$CommitMessage = "Init"
    )

    # 啟用嚴格模式
    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    # 切換到指定目錄
    $originalLocation = Get-Location
    Set-Location $Path

    # Git 包裝函式 - 自動檢查錯誤並拋出例外
    function git {
        & (Get-Command git.exe -CommandType Application) @args
        if ($LASTEXITCODE -ne 0) {
            Write-Error "Git command failed: git $($args -join ' ') (exit code: $LASTEXITCODE)"
        }
    }

    try {
        # ==================== 預檢查階段 ====================
        # 檢查 README 檔案是否已存在
        if (Test-Path $ReadmeFileName) {
            Write-Error "Error: $ReadmeFileName file already exists!"
        }
        # 檢查 Git 倉庫是否已存在
        if (Test-Path ".git") {
            Write-Error "Error: Git repository already exists!"
        }
        # 檢查 Git 命令是否可用
        try {
            git --version | Out-Null
        } catch {
            Write-Error "Error: Git is not installed or not in PATH!"
        }

        # ==================== 執行階段 ====================
        # 創建 README 檔案
        New-Item -Name $ReadmeFileName -ItemType File | Out-Null
        # 初始化Git倉庫
        git init
        # 添加檔案並提交
        git add $ReadmeFileName
        # 提交
        git commit -m $CommitMessage

    } catch {
        throw
    } finally {
        Set-Location $originalLocation
    }
}





PowerShell 產生隨機密碼

經常用到每次都要查有點煩了,乾脆弄個函式寫到系統中,呼叫的時候比較方便

在 PowerShell 中輸入 $PROFILE 會顯示出每次 PowerShell 載入時讀取的腳本,可以把以下函式寫到裡面去,這樣打開 PowerShell 只要輸入 nrp 就可以產出密碼了

(第一次創建的時候需要設定權限不然會錯,那個複製錯誤信息Google或問AI就可以解了)

以下是產密碼的函式

# Generate a random password
function New-RandomPassword {
    [Alias('nrp')]
    param (
        [Parameter(Position = 0)]
        [ValidateRange(1, 512)]
        [int]$Length = 15,
        [switch]$Symbols,
        [switch]$Ambiguous,
        [string]$IncludeCharacters,
        [string]$ExcludeCharacters
    ) $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    if (-not $Ambiguous) { $chars = $chars -replace '[lIO01]', '' }
    if ($Symbols) { $chars += '!@#$%^&*()-_=+' }
    if ($IncludeCharacters) { $chars += $IncludeCharacters }
    if ($ExcludeCharacters) { $chars = -join $chars.ToCharArray().Where{ $ExcludeCharacters.IndexOf($_) -lt 0 } }
    if ($chars.Length -eq 0) { Write-Error "Character set is empty after exclusions"; return }
    $rng = [Security.Cryptography.RandomNumberGenerator]::Create()
    try {
        $rng.GetBytes(($bytes = [byte[]]::new($Length * 8)))
        -join (0..($Length - 1)).ForEach({ $chars[[BitConverter]::ToUInt64($bytes, $_ * 8) % $chars.Length] })
    } finally { $rng.Dispose() }
} # New-RandomPassword

預設使用 New-RandomPassword 或是 ‘nrp’ 會產出 15 碼的隨機密碼 (預設不包含易造成混亂的 lIO01 字元)

如果需要複雜包含符號,可以使用 -Symbols 與 -Ambiguous 參數
要定義字元可以使用 -IncludeCharacters -ExcludeCharacters 參數
顯式指定與 Symbols / Ambiguous 有衝突時顯式優先級更高




2025年11月18日 星期二

git 允許當前檢出中的分支可以被推送

git 允許當前檢出中的分支可以被推送

git如果不是作為裸庫一般會把檔案檢出,可以看到並加入追蹤。在這種狀態下預設為了被免其他誤推送導致未儲存的檔案移除或是相衝是禁止的。

某些情況下臨時要測試,而且很清楚git原理與知道自己在幹麻這東西是有一定方便性的,以下是打開的指令

git config receive.denyCurrentBranch ignore 

在檢出目錄是乾淨的狀態下,就可以被推送了


具體的行為是檢出中的分支會隨著被推送到最新版本,當前檔案狀態會 stage 的形式保護住不會被更動,僅分支被更新。


2025年10月28日 星期二

Windows Server RDP 解除單一連接線制 (同時間可多人用同一個帳號)

Windows Server RDP 解除單一連接線制 (同時間可多人用同一個帳號)

這功能免費額度最大上限是同時2個連入,但大多數場合2個也很足夠用了


懶人包登錄檔設置指令是

REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fSingleSessionPerUser /t REG_DWORD /d 0 /f


從群組原則的話設定在這個路徑:
電腦設定 → 系統管理範本 → Windows 元件 → 遠端桌面服務 → 遠端桌面工作階段主機 → 連線





2025年10月17日 星期五

Ubuntu 安裝 Node.js 的兩種最佳實踐方式

Ubuntu 安裝 Node.js 的兩種最佳實踐方式

在 Ubuntu 系統中,Node.js 其實已經存在於官方套件庫中,可以直接透過 apt 安裝。但這個版本通常落後於官方最新版本

若希望取得最新版或方便切換多版本,建議使用以下兩種方式之一




方法一:使用 NodeSource(官方建議的 APT 外部庫)

這是最常見的「系統層級」安裝方式,由 NodeSource 提供編譯好的二進制檔。
它能讓你直接透過 apt 安裝最新的穩定版 Node.js。


官方來源參考: distributions/DEV_README.md

步驟:

# 加入 NodeSource 官方提供的最新 Node.js 安裝腳本(以 24.x 為例)
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -

# 安裝 Node.js 與 npm
sudo apt install -y nodejs

# 驗證版本
node -v
npm -v

優點:

  • 系統層級安裝,所有使用者可共用。
  • 可與 Ubuntu 的自動更新整合。
  • 適合伺服器、CI/CD 環境。

缺點:

  • 安裝或升級需使用 sudo
  • 若需多版本切換(例如 Node 16 與 22 共存)不方便。




方法二:使用 NVM(Node Version Manager)

這是由社群維護的 Node.js 版本管理器,能讓你以使用者身份安裝 Node.js(非系統層級)。
適合開發者或有多專案需求的環境。

官方來源參考: nvm-sh/nvm GitHub Repository

步驟:

# 下載並安裝 nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# 不想重新啟動 shell 時,執行:
\. "$HOME/.nvm/nvm.sh"

# 下載並安裝 Node.js:
nvm install 24

# 核對板本:
node -v # Should print "v24.10.0".
npm -v # 應會印出 "11.6.1"。

優點:

  • 不需 sudo 權限即可安裝。
  • 可快速切換 Node.js 版本。
  • npm 安裝時自動位於使用者目錄(例如 ~/.npm),更安全。

缺點:

  • 只對目前使用者有效。
  • 系統服務(如 systemd)不會直接使用 NVM 環境。



2025年10月1日 星期三

npm 反向代理 http 服務 cockpit (自動更新SSL)

使用 Nginx Proxy Manager(NPM)做反向代理並自動更新 SSL 憑證

這是連續的關於架設網站的系列

  1. 在 ubuntu 使用 docker 架設 nginx 靜態網站伺服器
  2. 使用 duckdns 轉發自建的靜態網頁伺服器
  3. npm 反向代理 nginx 靜態網站 (自動更新SSL)
  4. npm 反向代理 http 服務 portainer (私簽SSL)
  5. npm 反向代理 http 服務 cockpit (自動更新SSL)



這是接續 npm 反向代理 nginx 靜態網站 (自動更新SSL) 的進階篇,前面的東西不再重複,記得先回到這篇做完才接著繼續看這裡

在上一篇已經完成網站的建制,現在要把改成一個實際的別人做的專案做練習
這裡使用 cockpit 當範例,創建一個 duck.dns 對外網域的網站

這篇跟直接反向代理 nginx 的那篇差異在於,範例用的靜態網站完全沒有安全限制所以不需要特別處理,這裡抓一個正常有安全限制的服務 cockpit 來當範例



安裝 cockpit

這個有被內建在 ubuntu 中直接用 apt 就可以安裝了

sudo apt install cockpit
sudo systemctl enable --now cockpit.socket

安裝好之後就可以用 http:\localhost:9090 直接打開了



反向代理設定注意事項

在使用 Nginx Proxy Manager 等反向代理時,需要在 cockpit.conf 中進行以下設定:

  1. AllowUnencrypted = true - 允許後端 HTTP 通訊
    由於反向代理與 Cockpit 之間通常使用未加密的 HTTP 連接,此設定讓 Cockpit 接受來自代理服務器的 HTTP 請求,而 SSL/TLS 加密則由前端代理統一處理。
  2. ProtocolHeader = X-Forwarded-Proto - 識別真實協議類型
    反向代理會通過 X-Forwarded-Proto header 告知 Cockpit 用戶端實際使用的協議(HTTPS),確保 Cockpit 生成正確的重定向 URL 並避免瀏覽器混合內容警告。
  3. Origins = https://your-domain.com - 限制跨域請求來源
    明確指定允許的域名以防止 CSRF 攻擊,切勿使用 Origins = https: 或 Origins = *,否則任何第三方網站都能向您的 Cockpit 發送請求,造成安全風險。


編輯 cockpit.conf

sudo nano /etc/cockpit/cockpit.conf

輸入以下 (第三行記得改成自己的網域)

[WebService]
AllowUnencrypted = true
ProtocolHeader = X-Forwarded-Proto
Origins = https://cockpit.yourdomain.com

然後存檔即可



npm 反向代理

這裡用上一篇已經生成的網域就好,回到 npm 的 proxy 頁面把 Forward Port 從 8081 改成 9090 即可續用。

然後再瀏覽你自己的網域 https://chgsite.duckdns.org 應該就能看見你的網站了