Set up remote access on machines
General configuration to enable SSH
Install WSL2 on Windows. I’m still using Windows even though many less tech savvy people I know dislike Windows a lot and lowkey judge people like me who do not use Apple products anymore :-) Many desktop applications can only run on Windows including Visual Studio and running virtual machines on Mac or Linux is much slower than WSL2. With WSL2 working perfectly for developers and even WSL GUI in development I don’t see any reason to have another machine with other operating systems other than Windows because all I need is a browser and a Linux terminal. That’s it.
Generate a pair of public and private key in
~/.ssh/directory if you don’t have one for authentication:ssh-keygen -t ed25519 -C "[email protected]"orssh-keygen -t rsa -b 4096 -C "[email protected]"if your legacy system does not support the ed25519 algorithm and runssh-add /path/to/id_your_private_keyto activate the new private key.Modify configuration for ssh at
/etc/ssh/sshd_config, Un-comment ListenAddress to0.0.0.0, disable password authentication and enable public-key authentication for safety reasons. If you are running SSH server on WSL, Change to port2222or whatever you like except22because22is reserved for Windows system by default and WSL2 is a subsystem inside Windows so it’s highly recommended to change the port for the security reason. Finally, don’t forget to restart the SSH server withsudo service ssh restartto take effect.Start SSH server:
sudo apt install openssh-serverandsudo service ssh startcheck status with the command:sudo systemctl status ssh(It’s not working on WSL2 because drivers are not well supported so far in WSL2) or runsudo service ssh status.Create folder
~/.sshand file~/.ssh/authorized_keysif they don’t exist and a file authorized_keys inside it to store public keys.cat /path/to/id_rsa.pub >> ~/.ssh/authorized_keysReady to ssh from local machine:
ssh username@localhost -p 2222 -i /path/to/id_your_private_key
Windows SSH setup with WSL
Remote Desktop on Windows is easy to set up but it is not ideal for developers who just want a Linux terminal on WSL. SSH service is disabled on WSL by default and running SSH service on WSL may require you to enter the password. Apparently, no one would like to enter password for a startup task on Windows every time.
Change default shell to bash
sudo usermod --shell /bin/bash MY_USERNAMEbecause if you use other shells like fish, it may not run bash shell script correctly for example when setting variables. The best practice is to stick with bash shell but switch back to fish or other shells later. Inside.bashrcor.bash_profilewe can still callexec fishto initialize fish shell and replace the interactive bash shell after initialization of SSH service and other configs are done.Add current user into
sudogroupsudo usermod -aG sudo MY_USERNAMEorsudo adduser MY_USERNAME sudowhich means the current user insudogroup can be elevated to enjoy all privileges as the root user.Modify
~/.bash_profilefor interactive shell (not~/.bashrcbecause it is only for non-interactive bash shell like a new terminal window) to start SSH server after login. Open~/.bash_profileto add two lines:in order to check processes with1
2ps -C sshd > /dev/null && echo "sshd is running" || sudo service ssh start
exec fishps -Cto see if the SSH service is running otherwise start the SSH service. After that let’s switch it back to fish shell since we are done setting up configs in bash.Add your username to a sudo config file so we can execute commands freely without entering passwords. Create a sudoer profile
touch /etc/sudoers.d/MY_USERNAMEAdd the following line:MY_USERNAME ALL=(ALL) NOPASSWD:ALLor you can add it to/etc/sudoersas well.Finally, you will need to configure the ssh server to start without requiring password. Run the command
sudo visudoand add this line to the end of the file:%sudo ALL=NOPASSWD: /usr/sbin/sshd.
Run SSH service on WSL2 on startup
WSL won’t started until you manually start it with commands or click on GUI. Unlike WSL that shares the IP with host Windows machine, the IP of the new WSL2 is assigned dynamically every time WSL2 is started or rebooted. We need to run a task at startup to start WSL2, enable SSH service and forward the designated port to host machine.
Create a powershell script
sshd.ps1to start the WSL, get the current IP, forward the port and modify the Windows firewall rules. We don’t have to separately start WSL again because the commandwsl hostname -Iin the powershell script already started WSL. A gist from daehahn/wsl2-network.ps1 on GitHub that has more features to configure WSL network. TODO: Now we still have to manually confirm and switch to a new Adminstrator terminal process to run the powershell script that needs elevation every time Windows starts. It’s awful but I don’t find a good way to bypass the restriction even after I setSet-ExecutionPolicy -ExecutionPolicy Bypass -Scope XXXto all scopes.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# Change execution policy to execute powershell script if permission is denied
# Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Elevate the administrator priviledge with the following command
# Start-Process Powershell -Verb runAs
# Reset all rules
# netsh int portproxy reset all
# Elevation needed for netsh, start new process
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
# Relaunch as an elevated process:
Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path),"$Args runas" -Verb RunAs
exit
}
$wsl_ip = (wsl hostname -I).trim()
Write-Host "WSL2 Machine IP: ""$wsl_ip"""
netsh interface portproxy add v4tov4 listenport=2222 connectport=2222 connectaddress=$wsl_ip
# Set a rule in Firewall to allow inbound connection in port 2222
netsh advfirewall firewall add rule name=”Open Port 2222 for WSL2” dir=in action=allow protocol=TCP localport=2222
# Print all network rules
netsh interface portproxy show v4tov4Save the file and move it to a more accessible location, e.g.
mv sshd.ps1 /mnt/c/Users/YourUserName/Documentsin Linux file system orC:\Users\YourUserName\Documents\sshd.ps1on Windows. Make sure to match the path to your own username.Create a
sshd.cmdfile that calls the powershell script we just created and can be directly called on startup. The execution policy has to be set to unrestricted mode for some commands likenetshin the powershell script. Here is the official guide on how to write startup task in Windows: https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-startup-tasks-common1
2
3# Comment this line for now because it does not work on startup if not manually run from Administrator powershell
# PowerShell -Command "Set-ExecutionPolicy Unrestricted" >> "%TEMP%\StartupLog.txt" 2>&1
PowerShell C:\Users\YourUserName\Documents\sshd.ps1 >> "%TEMP%\StartupLog.txt" 2>&1Type
runon start menu or use shortcutWin + Rto run commands. Typeshell:startupand copy thesshd.cmdfile over to the Startup folder.Optionally, you can forward the port on your router so your home server can be accessed from everywhere in the world.
Create a Media Server on your desktop
After some efforts searching around and testing out several open source media server software, I’m pretty sure that Jellyfin is a very option and easy to set up on your machine. I set it up as a Windows service so it will keep running in the background secretly without showing up in the tray. The whole Jellyfin setup process can be done through the web interface from http://127.0.0.1:8096 locally and you just need to mount your music or movie folder to Jellyfin media server.
However, you cannot access your media server outside the local network in your home unless you forward the port but if you do direct port forwarding on port 8096, the service will deny access because it is a huge security issue to transmit plain data on the public network. The easiest solution is to use HTTPS enabled reverse proxy to mitigate the security risk mentioned above. Luckily, we have an one-liner perfect solution by using Caddy - Powerful, enterprise-ready, open source web server with automatic HTTPS that automatically creates a production ready reverse proxy server and manages the SSL certificate for you like magic! Caddy serves public DNS names over HTTPS using certificates from a public ACME CA such as Let’s Encrypt or ZeroSSL.
Forward
port 80for HTTP andport 443for HTTPS on your router so you can directly visit your home IP as an encrypted website later.Use Dynamic DNS service to get the IP address of your machine if it’s constantly changing. I recommend DuckDNS that send your IP to their website every five minutes by default. No extra software is needed and you only need to send some HTTP request to their server with your token using for example
crontabto schedule the task.After you installed
Caddycommand line tools on your local machine, one simple line solves all problems for you:caddy reverse-proxy --from public-domain-points-to-your-hosted-service.com --to 127.0.0.1:8096, it runs a reserve proxy that mapsport 8096for Jellyfin service toport 443with HTTPS and certificates enabled and now your media server website can be accessed from your public domain that points back to your home server.The process created by our one-liner-solves-all command will exit after you close the terminal so we need to put our config into
Caddyfile.Caddywill load it at startup and run the reverse proxy in the background. Since we only have one port for HTTPS traffic, we may want to use subpath like mydomain.com/jellyfin to access the service.If the path of the request is matched in1
2
3
4
5
6public-domain-points-to-your-hosted-service.com {
handle /jellyfin/* {
reverse_proxy /jellyfin/* 127.0.0.1:8096
}
reverse_proxy 127.0.0.1:8000
}/jellyfin/*, it will be forwarded through the reverse proxy otherwise the traffic is abandoned or in this case forwarded to another port.Go to the Jellyfin Web interface and add a custom subdirectory to the server URL. For example: set
<baseurl>to/jellyfininhttp://example.com/<baseurl>so the reverse proxy only forwards requests when their subpath contains/jellyfinat the beginning.Run Caddy as a service
caddy start --config Caddyfileand now you can access your home media server from your public domain inyourdomain.com/jellyfin/and stop it withcaddy stop.
Raspberry Pi Server Setup
Here is the most comprehensive official documentation Raspberry Pi Documentation
SSH connection via USB
Imagine you only have a Pi and SD card without another pair of screen, keyboard and mouse or you are too lazy to unplug everything from your desktop and plug into your Pi for setup. With a little modification on the image of Pi we can directly SSH into the Pi from another machine under the same local network via USB adapter, which enables the Pi to access the network through USB. The real SSH service by default is still not turned on until you set it up in raspi-config. * Open the root folder of the SD card, open config.txt and append dtoverlay=dwc2 to the end. * Open cmdline.txt and append modules-load=dwc2,g_ether leaving only one space between the word rootwait and the new text (otherwise it might not be parsed correctly). * Create a new empty file named ssh to enable SSH access because by default SSH is disabled on Pi. * Connect to Pi with command ssh [email protected] and default password is raspberry.
Once we have SSH access to the Pi, we can connect the Pi to cable network or Wifi instead of USB adapter. The next step is to disable the password and add public key to ~/.ssh/authorized_keys because password authentication is too dangerous.