The photo library hosted on a Raspberry Pi machine and accessible via local network. Photo library works with the HDD attached to Raspberry PI. All components of the application are run natively on a Linux OS without Docker containers. There is a Powershell script which can rollout next versions of application from dev machine to Raspberry server. But to make this rollout working, there are some initial setup steps should be done on the Raspberry Pi manually.
- Install
sudo apt update
sudo apt full-upgrade
sudo apt install postgresql- Change postgres user
sudo su postgres
createuser pi -P --interactive
# enter password when prompted
exitcd /media
sudo setfacl -m u:pi:rwx pisudo apt install nginx
sudo systemctl start nginxsudo apt install imagemagick heif-gdk-pixbuf-
Change values in
appsettings.json -
Publish backend as self-contained app. And copy it to the raspberry:
cd ./backend/PhotoLibraryBackend
dotnet publish -c release -r linux-arm64 --self-contained
scp -r ./bin/release/net8.0/linux-arm64/publish/* pi@192.168.0.65:/home/pi/projects/photo-library/backend- Using ssh, add run permissions and run app (just for test, in next step, we should create a service to run it):
cd projects/photo-library/backend
chmod +x ./PhotoLibraryBackend
./PhotoLibraryBackend- Copy a service file
scp -r ./photo-library.service pi@192.168.0.65:/home/pi/projects/photo-library- Register a service as
systemctl
ssh:
#Copy service file to the system dir:
sudo cp photo-library.service /etc/systemd/system/photo-library.service
# Restart daemon
sudo systemctl daemon-reload
# Start services
sudo systemctl start photo-library.service
# Enable auto start
sudo systemctl enable photo-library.service- Migrate database on fitst start:
curl http://127.0.0.1:5000
curl http://127.0.0.1:5000/migrateIdentityDb- change values in
.env - build react app in production mode
cd frontend
npm run build
scp -r ./build/* pi@192.168.0.65:/home/pi/projects/photo-library/frontend- Setup nginx.config
cd /etc/nginx
sudo nano nginx.confAdd this to http section:
map $http_connection $connection_upgrade {
"~*Upgrade" $http_connection;
default keep-alive;
}
server {
listen 8850;
server_name example.com *.example.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Configuration for WebSockets
proxy_cache off;
# Configuration for ServerSentEvents
proxy_buffering off;
# Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
proxy_read_timeout 100s;
}
}sudo systemctl restart nginx.serviceInternally: http://127.0.0.1:5000
From outside: http://192.168.0.65:8850/swagger/index.html
- Add permissions to nginx to frontend folders:
sudo gpasswd -a www-data pi
chmod g+x /home/pi && chmod g+x /home/pi/projects && chmod g+x /home/pi/projects/photo-library && chmod g+x /home/pi/projects/photo-library/frontend && chmod g+x /home/pi/projects/photo-library/frontend/static && chmod g+x /home/pi/projects/photo-library/frontend/static/css && chmod g+x /home/pi/projects/photo-library/frontend/static/jsserver {
listen 8860;
server_name photo-library.com *.photo-library.com;
access_log /var/log/nginx/photo_library_frontend.log;
error_log /var/log/nginx/photo_library_frontend_error.log;
root /home/pi/projects/photo-library/frontend;
index index.html;
location / {
try_files $uri /index.html;
}
}sudo systemctl restart nginx.serviceThere is a powershell script
Before running the raspberry-deploy.ps1 script, create a raspberry-deploy.env and fill these parameters:
RASPBERRY_ADDR=pi@192.168.0.42
PHOTO_LIBRARY_LOCAL_PATH=../../../photo-library-lib
PHOTO_LIBRARY_LOCAL_DELETE_FOLDER=../../../photo-library-lib-deleted
PHOTO_DB_CONNECTION_STRING=Host=localhost;Database=photo;Username=postgres;Password=MyDocker6
IDENTITY_DB_CONNECTION_STRING=Host=localhost;Database=photo;Username=postgres;Password=MyDocker6
PHOTO_LIBRARY_BACKEND_URL=your-backend-local-url
POSITION_STACK_API_KEY=<API Key>
PHOTO_LIBRARY_BACKEND_DEV_URL=http://localhost:5101
TELEGRAM_BOT_TOKEN=<Your bot token>
TELEGRAM_CHAT_ID=<Your chat id>
GOOGLE_MAPS_API=<Your Api Key>- ssh:
sudo systemctl stop photo-library.service- dev machine:
cd ./backend/PhotoLibraryBackend
dotnet publish -c release -r linux-arm64 --self-contained
scp -r ./bin/release/net8.0/linux-arm64/publish pi@192.168.0.65:/home/pi/projects/photo-library- ssh:
sudo systemctl daemon-reload
sudo systemctl start photo-library.service- Search for the “botfather” telegram bot in the Telegram client.
- Type
/newbotto create a new bot. You need to specify the bot's screen name and username. If the bot is successfully created, you will see the bot's API token like356111742:cFiWcIKXX5SsYHDRDj34oa3YE. You must not share this token with anyone. - Create a public channel with a suitable name (the chat name started with
@we will need to get chat id in step 5). - Add your bot to the list of administrators of the created channel. At least, the bot must have permission to post messages.
- Get the chat ID, calling the
sendMessagemethod like this: HTTP POSThttps://api.telegram.org/bot[your-bot-token]/sendMessagewith this body as JSON:Response will contain the numeric chat id like{ "parse_mode": "Markdown", "text": "_Hello there_\r\nFrom *Postman*\r\nTa da", "chat_id": "[public chat id started with @]" }"id": -1001701183067, - Put the API token from step 2 and numeric chat id from step 5 into appropriate parameters in
appsettings.jsonor/and into env values in theraspberry-deploy.env - As soon as we got the numeric chat id, we can make a created in step 3 channel as private. We don't need that public name started from
@anymore.
- Host asp.net core in Linux with NGINX
- Raspberry Pi 4 specifications
Quad core Cortex-A72 (ARM v8) 64-bit SoC-> ARM 64 - RID catalog = Telegram bot api
# Some service tune commands
sudo systemctl stop photo-library.service
sudo systemctl disable photo-library.service
# Service logs
sudo journalctl -u photo-library.service
# Services list
sudo systemctl list-units --type=service --all
(q for exit)
# Service status
sudo systemctl status keycloak
(q for exit)
# Service status last 100 rows
sudo journalctl -u photo-library.service -n 100 --no-pager