The Raspberry Pi is an amazing device; I've always known it. Yet I never bought or used one because I was hesitant of using Linux due to it's complexities (but now with more experience programming, I was interested again), C# didn't work with Linux (the dotnet framework is now cross platform including Linux), and I didn't have a project that I wanted to use a Pi for. I just needed something to use a Raspberry Pi for.
The idea strikes, I need for a low cost server and realized that a Raspberry Pi would work perfect for my need. So after ordering my CanaKit from Amazon, I waited...after the longest 24 hours I received my kit. That night I realized a mistake I made! I assumed I had a MicroSD card but to my sad realization, I only had SD cards and I opted for the kit without a memory card. So after ordering the correct size memory cards, I had to wait another day.
Finally!!! I had everything I needed and was ready to begin setting up my home server. I went through installing my websites, then installing my dependencies like dotnet, supervisor, nginx, and ufw, and then finally updating my network firewall and DNS records. That doesn't mean I've got everything figured out. Shoot!! Today I'm still working out some kinks.
Hopefully this will help someone trying to setup their own server (or future me once I've forgotten the process).
Supplies
CanaKit - Raspberry Pi 4
4GB
Clear case
MicroSD Card
Ethernet cable
Home Desktop
MicroSD slot for writing
Internet
Pi Setup
The first step in any build is putting together the machine. The kit comes with a power cable, HDMI cable, heat sinks, case fan, and a case. Additionally a MicroSD card is required. The most difficult part of this step was handling the tiny parts. Total build time is five to ten minutes. Follow the supplied instructions to build your kit.
There are many different methods and OS's to complete your Raspberry Pi. I'm going to describe a high-level of what I did. Refer to your OS instructions for additional information.
To prepare the OS, follow Ubuntu's instructions. From another computer I used Ubuntu's imager to image Ubuntu Server onto a MicroSD card. The process was incredibly easy using the imager. I chose the server version of Ubuntu because the intention of this this Pi to be a home server and so a lighter OS is preferred. The image took a few minutes to complete as it wrote the OS to the memory card. Once completed, I installed the memory card into my Pi, plugged in the power and Ethernet cables and turned the Pi on. The Pi immediately spun to life.
Once powered, I used Putty, an SSH client, to connect to my Pi. Since I'm an admin on my home network I was able to get the IP from my router admin dashboard but Ubuntu's instructions provide alternative methods too.
Once connected, and after finishing the login process, run the following commands to ensure the server was updated:
sudo apt update
sudo apt upgrade
I needed to restart after the upgrades: sudo shutdown -r
Installing Dependencies
Once the Raspberry Pi is ready then I was ready to install my dependencies. I downloaded my applications' source files using Git from GitHub.
Besides my application's source, there are a few applications that will make managing services/websites/application much easier. Install the following:
nginx will be used as our reverse proxy; it helps us connect external traffic to apps running locally
supervisor will maintain our app's startup and shutdown
ufw is optional; this will be used to configure the firewall rules
sudo apt install nginx
sudo apt install supervisor
sudo apt install ufw
Dotnet
For installing .NET, Microsoft's instructions is helpful but I was a user that received the Unable to locate package dotnet-sdk-X.X
error. Using apt-get failed to install dotnet for me. Instead I followed the manual install instructions to install .NET:
wget https://download.visualstudio.microsoft.com/download/pr/de47cbe2-f75f-44c5-8250-7960a36d6591/76cfdbfb7bf17cce27378a9fddd969a6/dotnet-sdk-3.1.404-linux-arm64.tar.gz
mkdir -p "$HOME/dotnet" && tar zxf dotnet-sdk-3.1.404-linux-arm64.tar.gz -C "$HOME/dotnet"
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet
This only temporarily adds dotnet to your PATH though. One way to make it more permanent is to modify your user's .bashrc
file and add export PATH=$PATH:$HOME/dotnet
as the last line of your the file.
Now our dotnet application should build and run locally.
Configure Supervisor
Add a config for supervisor:
sudo vim /etc/supervisor/config.d/mywebsite.conf
Fill the config with instructions to start your application:
[program:mywebsite-website]
command=/home/ubuntu/dotnet/dotnet /home/ubuntu/apps/MyWebsite/MyWebsite.dll
directory=/home/ubuntu/apps/MyWebsite
autostart=true
autorestart=true
stderr_logfile=/var/log/mywebsite-website.err.log
stdout_logfile=/var/log/mywebsite-website.out.log
environment=ASPNETCORE_ENVIRONMENT=production,ASPNETCORE_URLS=http://localhost:5000
user=www-data
stopsignal=INT
Caution - The log files must be placed in a directory that exists or where the user has write access. One way to check if supervisor started up correctly is using sudo service supervisor status and reviewing the output.
Configure Nginx - A Reverse Proxy
Add a config for nginx:
sudo vim /etc/nginx/sites-available/mywebsite.conf
Fill the config with the correct listening and fowarding ports and update the dns names if applicable:
server {
listen 80;
server_name mydomain.com anotherdomain.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Configure Firewalls
From your Pi you'll want to configure the firewall to allow incoming requests. Using ufw
we just need to run one command sudo ufw allow 80/tcp
to allow our port to be available externally (outside of the Pi). Ufw will also manage persisting the firewall rules for when your machine is restarted.
Caution - Installing multiple firewall programs that persist settings like ufw and iptables-persistent will cause problems.
Port Forwarding There is another firewall that needs to be updated if you want your website or application to be publicly available and not just within your home network; your network's firewall. Add a port forwarding rule to your raspberry pi so that nginx can handle any incoming traffic. If using a default http port then forward port 80 traffic to your Pi. Otherwise, forward the external port configured in nginx.
Restart Services
The last things to do is cycle your services:
sudo service supervisor restart
sudo service nginx reload
Your application should now be available publicly.
Configure DNS
Interfacing with IP addresses can be difficult so you'll probably want to setup DNS records.
Using Namecheap, I setup A records to point to my IP Address. Even though I have multiple websites coming in at the same IP and port, nginx knows how to route the traffic. To enable proper routing you need to define the expected incoming DNS names and configure with server_name
(see nginx config sample). Also refer to nginx's official documentation as server_name has several configuration features.
Finally
Your website should be publicly available once your DNS records propagate the Internet. The one problem I did experience was I was unable to access the websites using the DNS name from within my local network. Using my cell phone I was able to connect after disabling my Wifi.
Overall, the setup did have some bumps but was smoother than I expected. I'm glad I pulled the trigger; I learned some things along the way. Even though the apps I installed were simple, I was able to build my confidence along the way. I'm already planning on how else I can leverage this amazing piece of silicon or get another Pi!