Setting up the server from scratch
This is all the commands I used when I set up the server from a clean image on January 10 after we migrated the email to the new provider.
Preparing SSH
First we rebuild the image from Ubuntu 22.04.
We reset the root password using Rescue -> Reset root password. I recommend then changing it to a new password once inside again (through passwd root
).
Login using the console GUI.
Go to /etc/ssh
and change the SSH server settings sshd_config
:
PermitRootLogin no
PasswordAuthentication no
Then we create a new user (-m creates home directory, then we add them to sudo group):
useradd -m backend
adduser backend sudo
Then do passwd backend
and set up a password.
Switch to the user using su backend
.
The default shell might not be bash (for example if your prompt starts with only '$'), in that case run:
chsh --shell /bin/bash
Create a new directory mkdir /home/backend/.ssh
. Enter this directory (using cd
) and then do nano authorized_keys
to open/create a new file there.
Paste in your SSH public key (!) (something like ssh-ed25519 .... tiptenbrink@tipc
) and save the file (Ctrl-X).
Then, ensure the file has the correct permissions:
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
SSH niceties
Install "xauth" (while logged in as root)
apt install xauth
Then, login to backend (su backend
) and log out again. If you're using a nice terminal emulator, like kitty, you need to add the xterm file to the server. To do this, one time append kitty +kitten
before your ssh command like:
kitty +kitten ssh backend@<ip here>
After that you can just login normally. Other terminal emulators might need other instructions.
From this point on we never need to be logged in as root anymore!
Update packages
sudo apt update
sudo apt upgrade
You might have to reboot after this: reboot
.
Install basic C ompiler
sudo apt install build-essential
Install Rust
Go to https://rustup.rs/
Run the listed script. Choose "Customize", then profile "minimal".
Install cargo binary install tools
cargo install cargo-quickinstall
cargo quickinstall cargo-binstall
Install nu, tidploy
cargo binstall nu
cargo binstall tidploy
Install GH CLI
Follow these instructions.
Login to DodekaComCom on GitHub
Using its password.
Setup gh
Login using gh auth login
, then use a correctly scoped auth token that you got from the DodekaComCom account.
Add backend
user to Docker group
sudo usermod -aG docker backend
Then logout and back in again.
Login to ghcr.io
docker login ghcr.io
Use another access token, this one only has to read the org and have access to packages.
Clone dodeka
gh repo clone dsav-dodeka/dodeka
Set tidploy auth key
Now, ensure all necessary secrets are accessible by the access token you're going to set. Then enter the dodeka
repository and do:
tidploy auth bws
Then enter the access token.
Deploy
Next, run:
tidploy deploy -d deploy/use/production
This will start the backend and database.
Optional: restore database
In case you have all the files from the volume that contained the database, you want to restore these. First, get them to the server, for example using scp
. We assume we have a folder called backup
in our current directory that contains all the Postgres files. Ensure the database is down again (using docker compose -p dodeka-production-latest down
).
Then you can do:
docker run --rm -it -v ./backup:/from -v dodeka-db-volume-production-latest:/to alpine ash
This will put you into a container with the recently created, empty database at /to
and the backup at /from
. First, clean out the new folder using rm -rf *
while inside the /to
folder (don't do this in the container root directory!).
Then, you can run:
cd /from ; cp -av . /to
Now, restart the database. Everything should work now.
Setup nginx
Install it:
sudo apt install nginx
Start it:
sudo systemctl start nginx
For some extra details also see the full section on nginx and certificates.
Setup non-HTTPS config
Go to /etc/nginx
. Every file here is root-protected, so use sudo
before each of the following commands:
Go to the sites-available
subdirectory.
Do nano api.dsavdodeka.nl
and paste the following basic config:
server {
root /var/www/api.dsavdodeka.nl/html;
index index.html index.htm index.nginx-debian.html;
server_name api.dsavdodeka.nl;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
proxy_pass http://localhost:4241;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
server {
listen 80;
}
Create a symlink from the available to enabled:
sudo ln -s /etc/nginx/sites-available/api.dsavdodeka.nl /etc/nginx/sites-enabled/api.dsavdodeka.nl
If necessary, restart nginx:
sudo systemctl restart nginx
If you go to http://api.dsavdodeka.nl (not https) you should get "Hallo: Atleten"!
Certbot/Let's Encrypt
Install snap
sudo apt install snapd
Install certbot
sudo snap install --classic certbot
Run certbot
sudo certbot --nginx
First, enter your e-mail. Then it will give you a list of domains you want to install the certificate for, choose the number indicating api.dsavdodeka.nl
(probably 1).
Cleanup nginx config
You probably want to clean up your nginx config.
There might be a server block saying only:
server {
listen 80;
}
Delete this, the Certbot block should handle this now.
If necessary, restart nginx:
sudo systemctl restart nginx
Optional: install Python and Poetry
You can create database backups and migrate the database using Python. First, we need to install a Python version that has the same major version as the backend server requires.
To make it more easy to install new versions in the future, let's use pyenv
. I recommend not installing using homebrew, as that might interfere with some other core packages. Instead, use their install script and follow the instructions to put it into the path. These were, when last checked:
curl https://pyenv.run | bash
To add it to path and load it automatically: add to .bashrc
(in the server home folder):
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
Then, install the correct Python version using:
pyenv install <exact version>
Note that it will install Python from source, so this could take a while. If there is an error, take a look at all required packages that must be installed.
Then, go into the project directory and run pyenv local <exact version>
. Now, the Python version should be the correct one if you run python
.
Next, we will install Poetry to manage our dependencies. I recommend using pipx
(which you can just install using sudo apt install pipx
), so pipx install poetry
.
Then, we want to make our Poetry environment use the correct version. Most likely, the Python version was installed into: ~/.pyenv/versions/<version>/bin/python
, so then you can use (once you are in the backend/src
directory):
poetry env use ~/.pyenv/versions/<version>/bin/python
Now, we can run commands in our envrionment using poetry run <command>
.
Fin
That was it, with less than 300 lines of instructions can completely set up a Linux server from scratch, in a simple and secure way.