This guide covers setting up jot-server as a Windows Service, with optional Tailscale integration for secure remote access.
- Quick Start
- Installation
- Running as a Windows Service
- Tailscale Integration
- Firewall Configuration
- Useful Commands
- Troubleshooting
Open PowerShell as Administrator:
# Install jot-server
irm https://raw.githubusercontent.com/deca-inc/jot/main/apps/server/install.ps1 | iex
# Start the server
jot-server start
# Check status
jot-server statusOpen PowerShell and run:
irm https://raw.githubusercontent.com/deca-inc/jot/main/apps/server/install.ps1 | iexThis installs the binary to %LOCALAPPDATA%\jot-server\jot-server.exe and adds it to your PATH.
jot-server --version
jot-server statusNSSM (Non-Sucking Service Manager) makes it easy to run any application as a Windows service.
# Using winget
winget install NSSM.NSSM
# Or using Chocolatey
choco install nssm
# Or download from https://nssm.cc/downloadOpen PowerShell as Administrator:
# Set variables
$ServiceName = "JotServer"
$JotServerPath = "$env:LOCALAPPDATA\jot-server\jot-server.exe"
$DataDir = "$env:LOCALAPPDATA\jot-server\data"
# Generate JWT secret
$JwtSecret = [Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Max 256 }))
# Create data directory
New-Item -ItemType Directory -Force -Path $DataDir
# Install the service
nssm install $ServiceName $JotServerPath start --data-dir $DataDir
# Configure service parameters
nssm set $ServiceName AppDirectory "$env:LOCALAPPDATA\jot-server"
nssm set $ServiceName AppEnvironmentExtra "PORT=3000" "JWT_SECRET=$JwtSecret"
nssm set $ServiceName DisplayName "Jot Sync Server"
nssm set $ServiceName Description "Local sync server for Jot journaling app"
nssm set $ServiceName Start SERVICE_AUTO_START
# Configure logging
nssm set $ServiceName AppStdout "$env:LOCALAPPDATA\jot-server\logs\stdout.log"
nssm set $ServiceName AppStderr "$env:LOCALAPPDATA\jot-server\logs\stderr.log"
nssm set $ServiceName AppRotateFiles 1
nssm set $ServiceName AppRotateBytes 1048576
# Create logs directory
New-Item -ItemType Directory -Force -Path "$env:LOCALAPPDATA\jot-server\logs"nssm start JotServer
# Check status
nssm status JotServer
# Or using Windows services
Get-Service JotServerFor a simpler setup without additional software:
$ScriptPath = "$env:LOCALAPPDATA\jot-server\start-server.ps1"
@"
`$env:PORT = "3000"
`$env:JWT_SECRET = "$([Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Max 256 })))"
& "`$env:LOCALAPPDATA\jot-server\jot-server.exe" start --data-dir "`$env:LOCALAPPDATA\jot-server\data"
"@ | Out-File -FilePath $ScriptPath -Encoding UTF8$Action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"$env:LOCALAPPDATA\jot-server\start-server.ps1`""
$Trigger = New-ScheduledTaskTrigger -AtStartup
$Principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -RunLevel Highest
$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
Register-ScheduledTask -TaskName "JotServer" -Action $Action -Trigger $Trigger -Principal $Principal -Settings $SettingsStart-ScheduledTask -TaskName "JotServer"
# Check if running
Get-ScheduledTask -TaskName "JotServer" | Select-Object TaskName, StateWhy HTTPS? Android requires HTTPS connections by default - the Jot app will not connect to an HTTP-only server. Tailscale makes TLS certificate management easy, but you can also use Let's Encrypt, self-signed certs (with manual trust), or any other certificate authority.
Download from tailscale.com/download/windows or:
winget install Tailscale.TailscaleOpen Tailscale from the system tray and sign in.
tailscale status
# Look for your hostname, e.g., "my-pc.tail12345.ts.net"- Go to Tailscale Admin Console
- Enable MagicDNS
- Under HTTPS Certificates, enable HTTPS
Open PowerShell as Administrator:
# Create certs directory
$CertDir = "$env:LOCALAPPDATA\jot-server\certs"
New-Item -ItemType Directory -Force -Path $CertDir
Set-Location $CertDir
# Generate certificates (replace with your hostname)
tailscale cert my-pc.tail12345.ts.net
# Verify certificates were created
Get-ChildItem $CertDirIf using NSSM:
$CertDir = "$env:LOCALAPPDATA\jot-server\certs"
$Hostname = "my-pc.tail12345.ts.net" # Replace with your hostname
# Update service with TLS parameters
nssm set JotServer AppParameters "start --data-dir `"$env:LOCALAPPDATA\jot-server\data`" --tls-cert `"$CertDir\$Hostname.crt`" --tls-key `"$CertDir\$Hostname.key`""
# Restart the service
nssm restart JotServerIf using Task Scheduler, update the startup script:
$CertDir = "$env:LOCALAPPDATA\jot-server\certs"
$Hostname = "my-pc.tail12345.ts.net" # Replace with your hostname
$ScriptPath = "$env:LOCALAPPDATA\jot-server\start-server.ps1"
@"
`$env:PORT = "3000"
`$env:JWT_SECRET = "YOUR_JWT_SECRET_HERE"
& "`$env:LOCALAPPDATA\jot-server\jot-server.exe" start ``
--data-dir "`$env:LOCALAPPDATA\jot-server\data" ``
--tls-cert "$CertDir\$Hostname.crt" ``
--tls-key "$CertDir\$Hostname.key"
"@ | Out-File -FilePath $ScriptPath -Encoding UTF8
# Restart the task
Stop-ScheduledTask -TaskName "JotServer"
Start-ScheduledTask -TaskName "JotServer"Create a renewal script:
$RenewScript = "$env:LOCALAPPDATA\jot-server\renew-cert.ps1"
$Hostname = "my-pc.tail12345.ts.net" # Replace with your hostname
@"
Set-Location "`$env:LOCALAPPDATA\jot-server\certs"
tailscale cert $Hostname
# Restart jot-server
if (Get-Service JotServer -ErrorAction SilentlyContinue) {
Restart-Service JotServer
} else {
Stop-ScheduledTask -TaskName "JotServer"
Start-ScheduledTask -TaskName "JotServer"
}
"@ | Out-File -FilePath $RenewScript -Encoding UTF8Create a scheduled task for monthly renewal:
$Action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-ExecutionPolicy Bypass -File `"$env:LOCALAPPDATA\jot-server\renew-cert.ps1`""
$Trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 3am
Register-ScheduledTask -TaskName "JotServerCertRenewal" -Action $Action -Trigger $Trigger -RunLevel HighestTailscale handles firewall configuration automatically. No additional setup needed.
Allow jot-server through Windows Firewall:
# Allow inbound connections on port 3000
New-NetFirewallRule -DisplayName "Jot Server" `
-Direction Inbound `
-LocalPort 3000 `
-Protocol TCP `
-Action Allow
# Or allow the application
New-NetFirewallRule -DisplayName "Jot Server App" `
-Direction Inbound `
-Program "$env:LOCALAPPDATA\jot-server\jot-server.exe" `
-Action AllowTo verify:
Get-NetFirewallRule -DisplayName "Jot Server*" | Format-Table Name, DisplayName, Enabled# Start the service
nssm start JotServer
# Stop the service
nssm stop JotServer
# Restart the service
nssm restart JotServer
# Check status
nssm status JotServer
# Edit service configuration
nssm edit JotServer
# Remove the service
nssm remove JotServer confirm# Using PowerShell
Start-Service JotServer
Stop-Service JotServer
Restart-Service JotServer
Get-Service JotServer
# Using sc.exe
sc.exe start JotServer
sc.exe stop JotServer
sc.exe query JotServer# Start the task
Start-ScheduledTask -TaskName "JotServer"
# Stop the task
Stop-ScheduledTask -TaskName "JotServer"
# Check status
Get-ScheduledTask -TaskName "JotServer" | Select-Object TaskName, State
# Disable the task
Disable-ScheduledTask -TaskName "JotServer"
# Enable the task
Enable-ScheduledTask -TaskName "JotServer"
# Remove the task
Unregister-ScheduledTask -TaskName "JotServer" -Confirm:$false# View recent stdout log
Get-Content "$env:LOCALAPPDATA\jot-server\logs\stdout.log" -Tail 50
# Follow logs in real-time
Get-Content "$env:LOCALAPPDATA\jot-server\logs\stdout.log" -Wait -Tail 20
# View error log
Get-Content "$env:LOCALAPPDATA\jot-server\logs\stderr.log" -Tail 50
# View Windows Event Log for NSSM
Get-EventLog -LogName Application -Source nssm -Newest 20# Check server status
jot-server status
# List connected devices
jot-server devices
# Test HTTP endpoint
Invoke-RestMethod http://localhost:3000/
# Test HTTPS endpoint (with Tailscale)
Invoke-RestMethod https://my-pc.tail12345.ts.net:3000/
# Test API status
Invoke-RestMethod http://localhost:3000/api/status# Check Tailscale status
tailscale status
# Get your Tailscale IP
tailscale ip -4
# Generate certificate
tailscale cert my-pc.tail12345.ts.netCheck logs first:
Get-Content "$env:LOCALAPPDATA\jot-server\logs\stderr.log" -Tail 100Common issues:
-
Port already in use
# Check what's using the port Get-NetTCPConnection -LocalPort 3000 | Select-Object LocalPort, OwningProcess Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess # Change port in service configuration
-
Binary not found
# Verify the binary exists Test-Path "$env:LOCALAPPDATA\jot-server\jot-server.exe" # Reinstall if missing irm https://raw.githubusercontent.com/deca-inc/jot/main/apps/server/install.ps1 | iex
-
Permission issues
# Ensure directories exist New-Item -ItemType Directory -Force -Path "$env:LOCALAPPDATA\jot-server\data" New-Item -ItemType Directory -Force -Path "$env:LOCALAPPDATA\jot-server\logs"
-
Service won't start
# Check NSSM event log Get-EventLog -LogName Application -Source nssm -Newest 10 # Verify service configuration nssm get JotServer Application nssm get JotServer AppParameters nssm get JotServer AppDirectory
-
Service keeps stopping
# Check exit code nssm get JotServer ExitActions # View stderr log for errors Get-Content "$env:LOCALAPPDATA\jot-server\logs\stderr.log"
-
Certificate not found
# Verify certificates exist Get-ChildItem "$env:LOCALAPPDATA\jot-server\certs" # Regenerate Set-Location "$env:LOCALAPPDATA\jot-server\certs" tailscale cert my-pc.tail12345.ts.net
-
Certificate permission issues
# Check file permissions Get-Acl "$env:LOCALAPPDATA\jot-server\certs\*.key" | Format-List # Ensure the service account can read them icacls "$env:LOCALAPPDATA\jot-server\certs" /grant:r "$env:USERNAME:(OI)(CI)F"
-
Can't connect from other devices
# Verify Tailscale is connected tailscale status # Test connectivity from the other device ping my-pc.tail12345.ts.net
-
Firewall blocking connections
# Check firewall rules Get-NetFirewallRule -DisplayName "*Jot*" | Format-Table Name, Enabled, Direction # Temporarily disable firewall to test (re-enable after!) Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False # Test, then re-enable: Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
-
Antivirus blocking
Some antivirus software may block jot-server. Add an exception for:
%LOCALAPPDATA%\jot-server\jot-server.exe- Port 3000 (or your configured port)
# Check for updates
jot-server update --check
# Install update
jot-server update
# After update, restart the service
nssm restart JotServer
# Or
Stop-ScheduledTask -TaskName "JotServer"
Start-ScheduledTask -TaskName "JotServer"