Skip to content

Instantly share code, notes, and snippets.

@simbo
Last active January 23, 2021 05:18
Show Gist options
  • Save simbo/887559c18f0838bbb1a4dcd761eb6810 to your computer and use it in GitHub Desktop.
Save simbo/887559c18f0838bbb1a4dcd761eb6810 to your computer and use it in GitHub Desktop.
Setting up Ubuntu 20.10 64bit Server on Raspberry Pi 4 B

Setting up Ubuntu 20.10 64-bit Server on Raspberry Pi 4 B

About

This document will guide you to create a raspberry pi as server for node.js apps in your local network.

To achieve this, the following software will be set up on the device:

  • nvm to be able to provide different node versions for different apps
  • mongodb to provide a database
  • pm2 to manage processes of node apps
  • nginx to serve as reverse proxy for node apps

Hardware Recommendations

Prepare SD Card

Download the Raspberry Pi Imager, start it and follow the instructions to create an image using the Ubuntu Server 20.10 64-bit image.

First Login

  • user: ubuntu
  • password: ubuntu

SSH is already set up, so you can skip connecting a physical keyboard and directly ssh ubuntu@<IP>.

You will be asked to change your password on the first login.

Create a custom User

# create user
sudo adduser <USER>

# grant sudo and common privileges
sudo usermod -aG sudo,adm,dialout,cdrom,floppy,audio,dip,video,plugdev,netdev,lxd <USER>

# after logging in as with your new user, remove the ubuntu user and its homedir
sudo pkill -u ubuntu
sudo deluser -remove-home ubuntu

Allow using sudo without Password

Run sudo visudo and edit the line for the sudoers group to this:

%sudo   ALL=(ALL:ALL) NOPASSWD:ALL

Copy SSH Key

Copy your ssh id from your local machine to the pi:

ssh-copy-id -i ~/.ssh/id_rsa.pub <USER>@<IP>

Set Locales, Timezone and Keyboard

# config locales
sudo dpkg-reconfigure locales

# config timezone
sudo dpkg-reconfigure tzdata

# check date/time and timesync settings
timedatectl status

# config keyboard
sudo dpkg-reconfigure keyboard-configuration

Update Packages and install Basics

sudo apt-get update
sudo apt-get --with-new-pkgs upgrade -y

Change Hostname

echo "pi-srv" > sudo tee /etc/hostname

Customize MOTD

sudo apt-get install -y toilet
sudo rm /etc/update-motd.d/10-help-text
sudo touch /etc/update-motd.d/00-at-first
sudo chmod +x /etc/update-motd.d/00-at-first
sudo nano /etc/update-motd.d/00-at-first
#!/bin/sh
toilet --termwidth --filter border --gay --font future -k "$(cat /etc/hostname)"
printf "$(cat /proc/device-tree/model)\n\n"

Customize bash Profile

Some things to add to ~/.bashrc:

HISTSIZE=5000
HISTFILESIZE=10000

PS1='\[\e[0;93;100m\]▌\u\[\e[0;30;100m\]@\[\e[0;93;100m\]\h▐\[\e[m\] \[\e[0;94m\]\w\[\e[m\] \[\e[0;90m\]\t\[\e[m\]\n\[\e[0;1;95m\]❯\[\e[m\] \[\e0'

alias ls='ls --color=auto --group-directories-first --human-readable'
alias ll='ls -AlCF'
alias la='ll -A'

Create a convenient Update Script

mkdir -p ~/bin
touch ~/bin/$(whoami)-update-packages
chmod +x ~/bin/$(whoami)-update-packages
nano ~/bin/$(whoami)-update-packages
#!/bin/sh
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo apt-get clean -y

Install node.js via nvm

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
source ~/.bashrc
nvm install 14
nvm alias default 14

Install yarn without node.js

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install --no-install-recommends yarn

Add this to your ~/.profile to add ~/.yarn/bin to your PATH:

PATH="$HOME/.yarn/bin:$PATH"

Setup nginx

# install
sudo apt-get install nginx

# edit nginx config (see below)
sudo nano /etc/nginx/nginx.conf

# edit site config (see below)
sudo nano /etc/nginx/sites-available/default

# test config
sudo nginx -t

# reload config
sudo nginx -s reload

# download pi favicon
sudo curl -L https://www.raspberrypi.org/favicon.ico -o /var/www/html/favicon.png

# remove nginx default page
sudo rm /var/www/html/index.nginx-debian.html

/etc/nginx/nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
  worker_connections 768;
}

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

/etc/nginx/sites-available/default:

#upstream app_upstream {
#  server localhost:3000;
#  keepalive 64;
#}

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  root /var/www/html;

  index index.php index.html index.htm;

  server_name pi-srv;

  autoindex on;
  autoindex_localtime on;
  autoindex_exact_size on;

  location / {
    try_files $uri $uri/ =404;
  }

  location = /favicon.ico {
    rewrite . /favicon.png;
  }

  #location = /app {
  #  return 302 /app/;
  #}

  #location /app/ {
  #  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  #  proxy_set_header X-Real-IP $remote_addr;
  #  proxy_set_header Host $http_host;
  #  proxy_http_version 1.1;
  #  proxy_set_header Upgrade $http_upgrade;
  #  proxy_set_header Connection 'upgrade';
  #  proxy_pass http://app_upstream/;
  #  proxy_redirect off;
  #  proxy_read_timeout 240s;
  #}
}

Setup MongoDB

# install
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org

# pin packages to current version
echo "mongodb-org hold" | sudo dpkg --set-selections
echo "mongodb-org-server hold" | sudo dpkg --set-selections
echo "mongodb-org-shell hold" | sudo dpkg --set-selections
echo "mongodb-org-mongos hold" | sudo dpkg --set-selections
echo "mongodb-org-tools hold" | sudo dpkg --set-selections

# edit config (see below)
sudo nano /etc/mongodb.conf

Using this config and below firewall setup, mongodb is accessible from your local network without authentication. See MongoDB Docs for more security.

/etc/mongodb.conf

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

net:
  port: 27017
  bindIp: 0.0.0.0

processManagement:
  timeZoneInfo: /usr/share/zoneinfo
  pidFilePath: /run/mongod/mongod.pid

Setup MongoDB Daemon

Fix PID-File in mongod service config by changing the respective line in /lib/systemd/system/mongod.service to:

PIDFile=/run/mongod/mongod.pid

Then...

# create folder for pidfile and set ownership to mongodb user
mkdir /run/mongod
chown mongodb:mongodb /run/mongod

# reload daemon config
sudo systemctl daemon-reload

# restart mongo daemon
sudo systemctl restart mongod

# check status
sudo systemctl status mongod

# autostart daemon after boot
sudo systemctl enable mongod

Setup logrotate.d for mongod

Create a logrotate config for mongod using this command:

sudo nano /etc/logrotate.d/mongod

Insert this config:

/var/log/mongodb/mongod.log {
  rotate 52
  weekly
  missingok
  compress
  delaycompress
  notifempty
  create 640 mongodb mongodb
  sharedscripts
  postrotate
    systemctl restart mongod
  endscript
}

You can test this config using sudo logrotate -f /etc/logrotate.d/mongod.

Setup PM2

# install pm2
yarn global add pm2

# display instructions to start pm2 as service
pm2 startup systemd -u $(whoami) --hp /home/$(whoami)

Setup logrotate.d for pm2

Create a logrotate config for pm2 using this command:

sudo nano /etc/logrotate.d/pm2-$(whoami)

Insert this config and replace <USER> with your username:

/home/<USER>/.pm2/pm2.log /home/<USER>/.pm2/logs/*.log {
  rotate 52
  weekly
  missingok
  notifempty
  compress
  delaycompress
  copytruncate
  create 0640 <USER> <USER>
}

You can test this config using sudo logrotate -f /etc/logrotate.d/pm2-$(whoami).

Setup Firewall

sudo apt-get install ufw

# deny all incoming traffic
sudo ufw default deny incoming

# allow ssh from local network
sudo ufw allow from 192.168.<SUBNET>.0/24 to any app OpenSSH

# limit ssh connections
sudo ufw limit ssh/tcp

# allow http(s) from local network
sudo ufw allow from 192.168.<SUBNET>.0/24 to any app "NGINX HTTP"
sudo ufw allow from 192.168.<SUBNET>.0/24 to any app "NGINX HTTPS"

# allow mongodb access from local network
sudo ufw allow from 192.168.<SUBNET>.0/24 to any port 27017

# enable firewall (WARNING: misconfiguration may lock you out!)
sudo ufw enable
sudo ufw status verbose

Cleanup

sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo apt-get clean -y
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment