.NET, Blazor 및 SignalR Core로 구축된 원격 제어 및 원격 스크립팅 솔루션입니다.
저를 도와주실 관리자를 찾고 있습니다! .NET 개발자이고 원격으로 계속해서 발전하는 데 관심이 있다면 Discord의 jaredatimmy
에서 DM을 보내주세요.
하위 레딧: https://www.reddit.com/r/remotely_app/
도커: https://hub.docker.com/r/immybot/remotely
튜토리얼: https://www.youtube.com/watch?v=t-TFvr7sZ6M (감사합니다, @bmcgonag!)
mkdir -p /var/www/remotely wget -q https://raw.githubusercontent.com/immense/Remotely/master/docker-compose/docker-compose.yml docker-compose up -d
지원되는 유일한 역방향 프록시는 Caddy이며 인터넷에 직접 연결되는 경우에만 가능합니다. Caddy의 기본 구성은 ASP.NET Core 및 SignalR이 올바르게 작동하는 데 필요한 모든 것을 제공합니다.
추가 방화벽이나 Nginx 등 다른 설정에서 네트워킹 문제가 있는 경우 토론 탭, Reddit 또는 다른 소셜 사이트에서 커뮤니티 지원을 찾아보세요. 원격 유지관리자는 가능한 모든 환경 설정에 대한 지침과 지원을 제공할 수 없습니다.
즉, ASP.NET Core에서는 역방향 프록시 뒤에 있을 때 X-Forwarded-Proto
, X-Forwarded-Host
및 X-Forwarded-For
헤더를 설정해야 합니다. 이는 각각 체계(http/https), 원래 요청의 URL 및 클라이언트의 IP 주소와 연관됩니다. 결과 구성표와 호스트는 설치 프로그램과 데스크톱 클라이언트에 삽입되므로 요청을 보낼 위치를 알 수 있습니다. 클라이언트 IP 주소는 장치 정보에 사용됩니다.
원격 코드는 이러한 값을 구문 분석하거나 처리하지 않습니다. 이는 ASP.NET Core의 기본 제공 미들웨어에 의해 내부적으로 수행됩니다. 값이 예상대로 나타나지 않으면 헤더가 누락되었거나, 올바른 값을 포함하지 않았거나, 올바른 형식이 아니거나, 알려진 프록시 체인을 통해 전달되지 않았기 때문입니다(아래 참조).
주입 공격을 방지하기 위해 ASP.NET Core는 기본적으로 루프백 주소에서 전달된 헤더만 허용합니다. 또한 docker-compose 파일에 정의된 Docker 게이트웨이 IP(172.28.0.1)를 원격으로 추가합니다. 기본이 아닌 구성을 사용하는 경우 서버 구성의 KnownProxies
배열에 모든 방화벽 및 역방향 프록시 주소를 추가해야 합니다.
역방향 프록시를 올바르게 구성할 수 없는 경우 최소한 서버 구성 페이지에서 Force Client HTTPS
설정하여 HTTPS 구성표를 강제로 사용할 수 있습니다.
이 주제에 대한 Microsoft의 전체 문서는 여기에서 찾을 수 있습니다: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer
Remotely에 대한 데이터는 Docker 호스트의 /var/www/remotely/
에 마운트될 /app/AppData
아래의 컨테이너에 저장됩니다.
이 폴더에는 Remotely.db와 서버에서 생성된 로그가 포함됩니다.
이러한 파일은 새로운 원격 컨테이너를 분해하고 설정해도 유지됩니다.
Docker가 아닌 버전의 Remotely에서 업그레이드하는 경우 이전 설치의 DB 파일을 덮어쓰십시오.
사이트를 인터넷에 노출하려면 Caddy를 역방향 프록시로 사용하세요.
처음 실행하는 경우 메인 페이지에서 Register
버튼을 클릭하여 계정을 만드세요.
조직은 사용자, 장치 및 기타 데이터 항목을 단일 풀로 그룹화하는 데 사용됩니다.
기본적으로 서버에는 하나의 조직만 존재할 수 있습니다.
Register
버튼이 사라집니다.
사람들은 더 이상 스스로 계정을 만들 수 없습니다.
자체 등록을 허용하려면 MaxOrganizationCount
를 늘리거나 -1로 설정합니다(구성 섹션 참조).
이 계정은 서버 관리자이자 조직 관리자가 됩니다.
계정에 대한 조직이 자동으로 생성됩니다.
HTTP 로깅을 활성화하여 헤더를 포함하여 서버 로그의 모든 요청과 응답을 볼 수 있습니다. 이는 역방향 프록시, API 또는 SignalR 문제를 디버깅하는 데 도움이 될 수 있습니다. 이 옵션은 서버 구성 페이지에서 활성화할 수 있습니다.
위 사항을 변경한 후 변경 사항을 적용하려면 컨테이너를 다시 시작해야 합니다.
다음 단계에서는 원격 서버 및 클라이언트를 구축하기 위해 Windows 11 시스템을 구성합니다.
Visual Studio 2022를 설치합니다.
.NET SDK(최신 버전).
MSBuild(Roslyn 컴파일러를 자동 선택)
NuGet 대상 및 빌드 작업.
.NET 프레임워크 4.8 SDK.
디버깅 및 개발을 위해서는 관련된 모든 워크로드가 필요합니다.
ASP.NET 및 웹 개발
.NET 데스크탑 개발
.NET Core 크로스 플랫폼 개발
링크: https://visualstudio.microsoft.com/downloads/
다음 워크로드를 선택해야 합니다.
다음 개별 구성 요소를 선택해야 합니다.
Windows용 Git을 설치합니다.
링크: https://git-scm.com/downloads
최신 LTS 노드를 설치합니다.
링크: https://nodejs.org/
git 저장소 복제: git clone https://github.com/immense/Remotely --recurse
디버깅할 때 에이전트는 미리 정의된 장치 ID를 사용하고 https://localhost:5001에 연결합니다.
개발 환경에서 서버는 모든 연결 에이전트를 첫 번째 조직에 할당합니다.
위의 두 가지를 사용하면 에이전트와 서버를 함께 디버그하고 목록에서 장치를 볼 수 있습니다.
생성된 첫 번째 계정은 해당 계정에 대해 생성된 서버와 조직 모두의 관리자가 됩니다.
조직 관리자는 조직 페이지 및 자신의 조직과 관련된 서버 로그 항목에 액세스할 수 있습니다. 서버 관리자는 서버 구성 페이지에 액세스할 수 있으며 조직에 속하지 않는 서버 로그 항목을 볼 수 있습니다.
계정 섹션에는 빠른 지원 클라이언트 및 Windows 설치 프로그램에 적용되는 브랜딩 탭이 있습니다.
그러나 클라이언트는 브랜드 정보를 검색할 수 있도록 앱에 하드 코딩된 서버 URL을 사용하여 소스에서 구축되어야 합니다.
데이터베이스 공급자, 연결 문자열 및 ASP.NET Core 포트는 docker-compose.yml
의 환경 변수를 통해 구성할 수 있습니다.
다른 모든 구성은 로그인한 후 서버 구성 페이지에서 수행됩니다.
AllowApiLogin: API 컨트롤러를 통한 로그인을 허용할지 여부입니다. 이 접근 방식보다는 API 액세스 토큰을 사용하는 것이 좋습니다.
BannedDevices: 금지할 장치 ID, 이름 또는 IP 주소의 배열입니다. 연결을 시도하면 제거 명령이 즉시 다시 전송됩니다.
DataRetentionInDays: 로그 및 기타 데이터가 서버에 보관되는 기간입니다. 무기한 유지하려면 -1로 설정합니다(권장되지 않음).
DBProvider: 세 개의 연결 문자열(상단) 중 어느 것이 사용될지 결정합니다. 데이터베이스 유형에 적합한 DB 공급자가 코드에 자동으로 로드됩니다.
EnableWindowsEventLog: Windows 이벤트 로그에 서버 로그 항목을 추가할지 여부입니다.
EnforceAttendedAccess: 무인 원격 제어 시도를 허용하라는 메시지가 클라이언트에 표시됩니다.
EnableRemoteControlRecording: 원격 제어 세션의 녹화를 서버에 저장할지 여부입니다.
/app/AppData/recordings
에 저장됩니다.
해당 보존은 DataRetentionInDays
에 의해 관리됩니다.
ForceClientHTTPS: 전달된 헤더가 잘못 구성된 경우에도 설치 프로그램과 데스크톱 클라이언트가 HTTPS 체계를 사용하도록 강제합니다.
알려진 프록시: 역방향 프록시가 다른 컴퓨터에 있고 요청을 원격 서버로 전달하는 경우 역방향 프록시 서버의 IP를 이 배열에 추가해야 합니다.
MaxOrganizationCount: 기본적으로 서버에는 하나의 조직이 존재할 수 있으며, 첫 번째 계정 등록 시 자동으로 생성됩니다. 이후에는 자체 등록이 비활성화됩니다.
다중 테넌시를 허용하려면 이 값을 -1로 설정하거나 특정 숫자로 늘리십시오.
RedirectToHttps: ASP.NET Core가 모든 트래픽을 HTTP에서 HTTPS로 리디렉션할지 여부입니다. 이는 동일한 작업을 수행하는 Caddy, Nginx 및 IIS 구성과 독립적입니다.
RemoteControlNotifyUsers: 무인 원격 제어 세션이 시작될 때 최종 사용자에게 알림을 표시할지 여부입니다.
RemoteControlRequiresAuthentication: 원격 제어 페이지에서 연결을 설정하기 위해 인증이 필요한지 여부입니다.
Require2FA: 사용자가 기본 앱을 사용하려면 먼저 2FA를 설정해야 합니다.
Smpt-: 자동 생성된 시스템 이메일(예: 등록 및 비밀번호 재설정)에 대한 SMTP 설정입니다.
테마: 사이트에 사용할 색상 테마입니다. 값은 "밝음" 또는 "어두움"입니다. 계정 - 옵션에서 사용자별로 구성할 수도 있습니다.
TrustedCorsOrigins: JavaScript를 통한 교차 출처 API 요청용입니다. 이 배열에 나열된 웹사이트는 API에 요청할 수 있습니다. 이는 대부분의 끝점에서 여전히 필요한 인증을 부여하지 않습니다.
UseHsts: ASP.NET Core가 HTTP 엄격한 전송 보안을 사용할지 여부입니다.
UseHttpLogging: 모든 HTTP 요청에 대한 로깅을 활성화합니다. 또한 전달된 헤더 처리 결과로 유효한 체계, 호스트 및 원격 IP 주소와 관련하여 ClientDownloadsController
에서 추가 로그 항목을 활성화합니다.
이 기능이 작동하려면 Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware
에 대한 로그 수준을 명시적으로 설정해야 합니다. 예제는 appsettings.json을 참조하세요.
기본적으로 원격에서는 SQLite 데이터베이스를 사용합니다. 처음 실행하면 appsettings.json의 SQLite 연결 문자열에 지정된 대로 파일이 생성됩니다.
ApplicationOptions
의 DBProvider
SQLServer
또는 PostgreSQL
로 변경하여 데이터베이스를 변경할 수 있습니다.
클라이언트에서 로그는 %ProgramData%RemotelyLogs
에 보관됩니다.
서버 컨테이너 내에서 로그는 /app/AppData/logs
에 기록되며, 이는 (기본적으로) 호스트의 /var/www/remotely/Logs
에 마운트됩니다.
기본 제공 ASP.NET Core 로그는 콘솔(stdout)에 기록됩니다. 원하는 경우 이를 파일로 리디렉션할 수 있습니다.
IIS에서는 stdoutLogEnabled를 true로 설정하여 web.config 파일에서 이 작업을 수행할 수 있습니다.
Windows 서버에서는 위의 로그를 Windows 이벤트 로그에 기록할 수도 있습니다.
이는 EnableWindowsEventLog를 true로 설정하여 서버 구성에서 활성화됩니다.
appsettings.json에서 로깅 수준 및 기타 설정을 구성할 수 있습니다.
추가 정보: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/
Windows: 최신 버전의 Windows 11만 테스트되었습니다. Windows 7 및 8.1에서는 작동하지만 Windows 7에서는 성능이 저하됩니다.
Windows 2019/2022도 작동하지만 정기적으로 테스트되지는 않습니다.
Linux: 최신 LTS 버전의 Ubuntu만 테스트되었습니다.
Ubuntu의 "빠른 지원" 클라이언트의 경우 먼저 다음 종속성을 설치해야 합니다.
libc6-dev
libxtst-dev
엑스클립
libx11-dev
libxrandr-dev
이상적으로는 실제 컴퓨터나 노트북에서 원격 제어를 수행하는 것입니다. 그러나 나는 리모콘을 모바일 장치에서 어느 정도 사용할 수 있도록 만들려고 노력했습니다. 컨트롤은 다음과 같습니다.
왼쪽 클릭: 한 번 탭
마우스 오른쪽 버튼 클릭: 길게 눌렀다가 놓습니다.
클릭 앤 드래그: 길게 누른 후 드래그
/get-support
에는 최종 사용자가 지원을 요청할 수 있는 페이지가 있습니다. 양식이 제출되면 기본 페이지의 그리드 위에 경고가 나타납니다.
이 페이지에 대한 바로 가기는 Program FilesRemotely
폴더에 있습니다. 원하는 곳에 복사할 수 있습니다. 설치 프로그램의 -supportshortcut
스위치를 사용하여 데스크탑에 자동으로 복사되도록 할 수도 있습니다.
.NET에는 프레임워크 종속 배포와 자체 포함 배포의 두 가지 배포 방법이 있습니다.
프레임워크 종속 배포를 위해서는 대상 컴퓨터에 .NET 런타임이 설치되어 있어야 합니다. 앱을 빌드하는 데 사용된 버전과 동일해야 합니다.
자체 포함 배포에는 런타임 복사본이 포함되므로 대상 컴퓨터에 이를 설치할 필요가 없습니다. 결과적으로 전체 파일 크기가 훨씬 커집니다.
.NET은 빌드 시 대상으로 지정된 런타임 식별자를 사용합니다.
링크: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
콘솔을 사용할 때 사용할 수 있는 몇 가지 바로 가기 키가 있습니다.
/ : 슬래시를 사용하면 쉘 간에 전환할 수 있습니다. 이름은 옵션 페이지에서 구성할 수 있습니다.
위쪽/아래쪽: 위쪽/아래쪽 화살표를 사용하여 입력 기록을 순환합니다.
Ctrl + Q: 출력 창을 지웁니다.
호스트 포트(왼쪽)는 docker-compose.yml
에서 구성할 수 있습니다. 컨테이너 포트(오른쪽)는 변경하면 안 됩니다. 자세한 내용은 작성 문서를 참조하세요.
원격으로 https://{your_server_url}/swagger
에서 찾아볼 수 있는 기본 API가 있습니다. 대부분의 엔드포인트에는 계정 - API 액세스로 이동하여 생성할 수 있는 API 액세스 토큰을 통한 인증이 필요합니다.
다른 웹사이트의 브라우저에서 API에 액세스할 때 웹사이트 원본 URL을 TrustedCorsOrigins 배열에 추가하여 앱 설정에서 CORS를 설정해야 합니다. CORS의 작동 방식에 익숙하지 않다면 계속 진행하기 전에 해당 내용을 읽어 보는 것이 좋습니다. 예를 들어 Remotely API에 로그인한 https://exmaple.com에 로그인 양식을 생성하려면 TrustedCorsOrigins에 "https://example.com"을 추가해야 합니다.
API에 대한 각 요청에는 "X-Api-Key"라는 헤더가 있어야 합니다. 값은 콜론으로 구분된 API 키의 ID와 비밀번호여야 합니다(예: [ApiKey]:[ApiSecret]).
다음은 API 요청 예시입니다.
POST https://localhost:5001/API/Scripting/ExecuteCommand/PSCore/f2b0a595-5ea8-471b-975f-12e70e0f3497 HTTP/1.1 Content-Type: application/json X-Api-Key: 31fb288d-af97-4ce1-ae7b-ceebb98281ac:HLkrKaZGExYvozSPvcACZw9awKkhHnNK User-Agent: PostmanRuntime/7.22.0 Accept: */* Cache-Control: no-cache Host: localhost:5001 Accept-Encoding: gzip, deflate, br Content-Length: 12 Connection: close Get-Location
다음은 쿠키 기반 로그인 API(JavaScript)를 사용하는 예입니다.
// Log in with one request, then launch remote control with another. fetch("https://localhost:5001/api/Login/", { method: "post", credentials: "include", mode: "cors", body: '{"email":"[email protected]", "password":"P@ssword1"}', headers: { "Content-Type": "application/json", } }).then(response=>{ if (response.ok) { fetch("https://localhost:44351/api/RemoteControl/Viewer/b68c24b0-2c67-4524-ad28-dadea7a576a4", { method: "get", credentials: "include", mode: "cors" }).then(response=>{ if (response.ok) { response.text().then(url=>{ window.open(url); }) } }) } }) // Log in and launch remote control in the same request. fetch("https://localhost:5001/api/RemoteControl/Viewer/", { method: "post", credentials: "include", mode: "cors", body: '{"email":"[email protected]", "password":"P@ssword1", "deviceID":"b68c24b0-2c67-4524-ad28-dadea7a576a4"}', headers: { "Content-Type": "application/json", } }).then(response=>{ if (response.ok) { response.text().then(url=>{ window.open(url); }) } })
Alerts API를 사용하면 장치 엔드포인트에 모니터링 및 경고 기능을 추가할 수 있습니다. 이 기능은 Remotely의 기본 목적에서 크게 벗어나지 않으면서 기본 RMM 유형 기능을 추가하기 위한 것입니다.
원격 웹사이트에 알림을 표시하고, 이메일을 보내고, 별도의 API 요청을 수행하도록 경고를 설정할 수 있습니다.
알림을 사용하려면 먼저 기기에서 사용할 API 토큰(또는 여러 토큰)을 만들어야 합니다. 그런 다음 예약된 작업이나 기타 반복 스크립트를 만들어 해당 작업을 수행하세요. 다음은 PowerShell을 사용하여 매일 디스크 공간을 확인하는 예약 작업을 만드는 방법의 예입니다.
$Trigger = New-JobTrigger -Daily -At "5 AM" $Option = New-ScheduledJobOption -RequireNetwork Register-ScheduledJob -ScriptBlock { $OsDrive = Get-PSDrive -Name C $FreeSpace = $OsDrive.Free / ($OsDrive.Used + $OsDrive.Free) if ($FreeSpace -lt .1) { Invoke-WebRequest -Uri "https://localhost:5001/api/Alerts/Create/" -Method Post -Headers @{ X-Api-Key="3e9d8273-1dc1-4303-bd50-7a133e36b9b7:S+82XKZdvg278pSFHWtUklqHENuO5IhH" } -Body @" { "AlertDeviceID": "f2b0a595-5ea8-471b-975f-12e70e0f3497", "AlertMessage": "Low hard drive space. Free Space: $([Math]::Round($FreeSpace * 100))%", "ApiRequestBody": null, "ApiRequestHeaders": null, "ApiRequestMethod": null, "ApiRequestUrl": null, "EmailBody": "Low hard drive space for device Maker.", "EmailSubject": "Hard Drive Space Alert", "EmailTo": "[email protected]", "ShouldAlert": true, "ShouldEmail": true, "ShouldSendApiRequest": false } "@ -ContentType "application/json" } } -Name "Check OS Drive Space" -Trigger $Trigger -ScheduledJobOption $Option