![]() |
|
SimpNas server with docker - home assistant, radicale , jellyfin & esphome (tutorial) - Printable Version +- PINE64 (https://forum.pine64.org) +-- Forum: ROCKPRO64 (https://forum.pine64.org/forumdisplay.php?fid=98) +--- Forum: RockPro64 Projects, Ideas and Tutorials (https://forum.pine64.org/forumdisplay.php?fid=104) +--- Thread: SimpNas server with docker - home assistant, radicale , jellyfin & esphome (tutorial) (/showthread.php?tid=12806) |
SimpNas server with docker - home assistant, radicale , jellyfin & esphome (tutorial) - GreyLinux - 01-17-2021 Outdated Tutorial: Please use as a guide only Hi all, I've been meaning to write this tutorial since last year , now right out of the gate I will say I am far from an expert. This is how I set up my NAS Server and docker containers , but I will gladly accept any critique of my setup and advice to better secure or improve the overall setup. To start with I did try OpenMediaVault, I got everything how I wanted it, however I felt that OpenMediaVault was too bloated for my needs and a little complicated in some of its options. Whilst on the Armbian forum ,seeking advice for getting the fan to work properly for my server (yes I did try tuxd3v 's ATS fan configuration but this didn't work after using a later kernel to get my sata card to work (more on that later)). I discovered SimpNAS , I posted a thread on this forum for all who are interested . SimpNAS was exactly what I was looking for , simple, elegant and easy . So to begin I setup OpenMediaVault and long story short I had issues with the pine64 supplied Sata card , I wont go in to detail here as there are many threads that describe this issue, here is some slight insight So I bought a marvell 88SE9230 Sata card , which so far has been absolutely amazing , rock solid no matter what I throw at it, but to use said card I had to use a newer kernel which as described in the thread resulted in me not being able to use ATS to control the fan. Now down to business , I have a rockpro64 with NAS case , tall heatsink , case fan, a marvell 88SE9230 Sata card, 2 SSD drives and a very decent SD card , the software is Armbian , with SimpNAS and docker installed and 6 containers - Nginx, Portainer, Homeassistant , Radicale caldav server , Jellyfin media server and EspHome for my home automation gadgets. home assistant and radicale are exposed to internet so they are accessible from outside my local network . so here are my instructions :
Code: rmmod pwm-fan
echo 0 > /sys/class/pwm/pwmchip1/export
echo 110 > /sys/class/pwm/pwmchip1/pwm0/duty_cycle
echo 500 > /sys/class/pwm/pwmchip1/pwm0/period
echo 1 > /sys/class/pwm/pwmchip1/pwm0/enable10. add udev rule so drives will show up nano /etc/udev/rules.d/99-marvell.rules. Code: ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x1b4b", ATTR{device}=="0x9230", RUN+="/bin/bash -c 'echo %k > /sys/bus/pci/drivers/ahci/bind'"11. reboot then type lsblk to see if drives are discovered 12. now install SimpNAS Code: wget https://simpnas.com/install.sh; bash install.sh13. follow setup wizard on url shown in terminal at the end of install . 14. login into SimpNAS admin panel using username administrator and password set during wizard 15. in admin panel Add Volumes to add the drives in SimpNAS 16. add users in user section 17. add shares to drives 18. at this point you now have your NAS setup , you can upload all the files you need to via samba 19. now onto portainer run this to get portainer installed and running, Docker is installed when SimpNAS is. Code: docker volume create portainer_data
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce20. now pull the images for the other containers, you can do this via the portainer UI (hence why I installed it first or via command line ) I like to do this now as it can take some time to pull the images ,although they will be installed with docker-compose later, if you prefer doing it all at once and don't want to know how docker works . Code: docker pull homeassistant/home-assistant:stable tomsquest/docker-radicale esphome/esphome nginx:latest21. now to install docker compose which will help later with renewing lets encrypt certificates via certbot . first we need a few packages Code: apt install python3 python3-pip python3-setuptools python3-dev libffi-dev22. then using the newly installed pip3 install wheel and docker-compose Code: pip3 install wheel
pip3 install docker-compose23.now lets create a docker-compose.yml file to start our containers and provide all the info they need to get running. When docker compose is run it will create all the necessary directories and files based on this docker-compose file . Code: version: '3.7'
services:
nginx:
depends_on:
- radicale
- homeassistant
image: nginx:latest
container_name: nginx_reverse_proxy
volumes:
- /etc/localtime:/etc/localtime:ro
- /root/nginx.conf:/etc/nginx/nginx.conf
- /root/nginx/error.log:/etc/nginx/error.log
- /root/nginx/access.log:/etc/nginx/access.log
- /etc/letsencrypt/:/etc/letsencrypt/
- /root/nginx/dhparams.pem:/etc/nginx/dhparams.pem
restart: unless-stopped
network_mode: host
radicale:
image: tomsquest/docker-radicale
container_name: radicale
ports:
- 127.0.0.1:5232:5232
init: true
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- SETUID
- SETGID
- CHOWN
- KILL
healthcheck:
test: curl -f http://127.0.0.1:5232 || exit 1
interval: 30s
retries: 3
restart: unless-stopped
volumes:
- /etc/localtime:/etc/localtime:ro
- /root/radicale/data:/data
- /root/radicale/config:/config:ro
- /root/radicale/users:/etc/radicale/users
- /root/radicale/log:/var/log/radicale/log
homeassistant:
container_name: home-assistant
image: homeassistant/home-assistant:stable
volumes:
- /etc/localtime:/etc/localtime:ro
- /root/homeassistant:/config
environment:
- TZ=Europe/London
restart: unless-stopped
network_mode: host
esphome:
image: esphome/esphome
volumes:
- /root/esphome/config:/config:rw
- /etc/localtime:/etc/localtime:ro
network_mode: host
restart: alwaysCode: user www-data;
worker_rlimit_core 500M;
worker_processes 1;
events {
worker_connections 1024;
}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
error_log /etc/nginx/error.log warn;
access_log /etc/nginx/access.log;
ssl_dhparam /etc/nginx/dhparams.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
ssl_stapling on;
ssl_stapling_verify on;
ssl_certificate /etc/letsencrypt/live/yourRadicaleAddress.duckdns.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourRadicaleAddress.duckdns.org/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/yourRadicaleAddress.duckdns.org/chain.pem;
ssl_session_cache shared:SSL:10m;
proxy_buffering off;
server {
listen 80;
server_name yourRadicaleAddress.duckdns.org;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourRadicaleAddress.duckdns.org;
location /radicale/ {
proxy_pass http://localhost:5232/;
proxy_set_header X-Script-Name /radicale;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Authorization;
}
}
server {
listen 80;
server_name yourHomeassistantAddress.duckdns.org;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourHomeassistantAddress.duckdns.org;
location / {
proxy_pass http://localhost:8123;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api/websocket {
proxy_pass http://localhost:8123/api/websocket;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}Code: openssl dhparam -out /root/nginx/cert/dhparam.pem -dsaparam 2048Code: [server]
hosts = 0.0.0.0:5232
max_connections = 15
# 100 Megabyte
max_content_length = 100000000
# 30 seconds
timeout = 20
[auth]
# Average delay after failed login attempts in seconds
delay = 600
type = htpasswd
htpasswd_filename = /etc/radicale/users
# encryption method used in the htpasswd file
htpasswd_encryption = md5
[storage]
filesystem_folder = /data/collectionsCode: apt install apache2-utils
htpasswd -c /root/radicale/users calendar28. now in order for radicale to work a radicale user and group needs to be created , more info can be gleamed from the provider of the Radicale docker container , here Code: addgroup --gid 2999 radicale
adduser --gid 2999 --uid 2999 --shell /bin/false --disabled-password --no-create-home radicale29. we are almost there now , just a few more steps and some optional ones at the end . Time to install fail2ban and certbot ( certbot obtains a lets encrypt certificate for us and will renew the cert via a cronjob specified later .) Code: apt install fail2ban certbotCode: cp jail.conf jail.local
nano jail.localCode: # "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24Code: nano /etc/fail2ban/jail.d/hass.conf
[hass-iptables]
enabled = true
chain = DOCKER-USER
filter = hass
action = iptables-allports[name=HASS]
logpath = /root/homeassistant/home-assistant.log
bantime = 3600
maxretry = 3Code: nano /etc/fail2ban/filter.d/hass.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
ignoreregex =
[Init]
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S32. A word of warning , if you are starting home assistant from new( as in no existing configuration file yet) I would disable fail2ban for now the reason is once restarted it will complain that there is no log located at /root/homeassistant/home-assistant.log . As stated in home assistants documentation linked above you need to have Code: logger:
logs:
homeassistant.components.http.ban: warningadded to your configuration file for this to work. If you have an existing home assistant configuration you can copy this across now to a home assistant directory located in the root home directory . add the above logger to the config file and then use the touch command to create the home-assistant.log file . Fail2ban can then be restarted or started if disabled and it wont complain about a missing file and will work when the conatiner is started and begins logging to said file . Code: systemctl restart fail2ban.servicenow check to see if the jail is up and working Code: fail2ban-client status hass-iptables33. Ok finally certbot , to get certbot to work port 80 and port 443 need to be open on your router and directed to the Rockpro64 IP address (I would also highly recommend that a static IP is set for the rockpro64 in your routers settings also ) lets begin by getting a lets encrypt certificate for the duckdns subdomains associated with our home assisatnt and radicale services. Code: certbot certonly --standalone -d yourRadicaleAddress.duckdns.org -d yourHomeassistantAddress.duckdns.orgnow certbot can renew this certificate for all associated subdomains when they have less than 30 days left until expiration this is done with a cronjob Code: crontab -eCode: @daily certbot renew --pre-hook "docker-compose -f /root/docker-compose.yml down" --post-hook "docker-compose -f /root/docker-compose.yml up -d"34. and finally lets start the containers and run them in the background . Code: docker-compose up -dnow you should be able to access the home assistant container at https://yourHomeassisantAddress.duckdns.org or locally at 192.168.1.120:8123(notice port 8123) you can access the Radicale container via https://yourRadicaleAddress.duckdns.org/radicale/ (notice the extension /radicale/ this was specified in the nginx.conf file earlier.) I would suggest closing the ports on teh router for the time being and accessing home assistant via its local IP address until you have a password and the setup complete then reopen the ports to access outside of you local network . this is of course not necessary if you have an existing configuration with home assistant and are transitioning to the Rockpro64 server . 36. the next few steps are optional , I installed Jellyfin as media server , I did this through the admin panel of SimpNAS under apps this creates a docker container for you and removes some of the steps to get it to access your media files correctly . of course you can install it manually like we did with the other containers and even use docker-compose by adding the container to the docker-compose.yml file , please note that when certbot renews the certificate it stops all the containers in this file before renewing the certs this is so port 80 and 443 are open for it to use and then it restarts the containers again. this will not happen to Jellyfin if installed manually or via the SimpNAS apps 37 . to top it all off, for those who want the firewall blocking ports on their local network to and from the rockpro64 , this is a little over kill as only port 80 and 443 are open to the outside world via the router, but I understand that some people like to add rules for local traffic to prevent spread locally of a virus or similar between machines on that network . I say this because it quite difficult to get a firewall working properly as docker provides it own set of rules to control the firewall and when you add rules of your own it might not work well with dockers rules if they work at all , so as suggested by a great article I found regarding this issue . here is a solution firstly create a iptables.conf file in /etc/ directory Code: *filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FILTERS - [0:0]
:DOCKER-USER - [0:0]
-F INPUT
-F DOCKER-USER
-F FILTERS
# BASIC Allow
-A INPUT -i lo -j ACCEPT
# Chain to FILTERS
-A INPUT -j FILTERS
-A DOCKER-USER -i eth0 -j FILTERS
# COMMON FIREWALL RULES
# ALLOW something
-A FILTERS -p all -j ACCEPT -m conntrack --ctstate ESTABLISHED,RELATED
-A FILTERS -p icmp --source 192.168.1.0/24 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 22 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 81 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 82 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 139 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 445 -j ACCEPT
-A FILTERS -p tcp --dport 80 -j ACCEPT
-A FILTERS -p tcp --dport 443 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 8123 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 8096 -j ACCEPT
-A FILTERS -p udp --source 192.168.1.0/24 --dport 1900 -j ACCEPT
-A FILTERS -p udp --source 192.168.1.0/24 --dport 7359 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 8000 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 9000 -j ACCEPT
-A FILTERS -p tcp --source 192.168.1.0/24 --dport 6052 -j ACCEPT
-A FILTERS -p udp --source 192.168.1.0/24 --dport 5353 -j ACCEPT
# DENY something
###################################################################
### special cases for servers
### please modify by the server
### end special cases
############################################################
# FINAL REJECT
# Optional logging
#-A FILTERS -m limit --limit 5/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7
-A FILTERS -p all -j REJECT
COMMITand add any rules you want after allow something, those above are just examples using the ports most of the services we have installed, use . next add these new rules from the file to the kernel to implement them Code: iptables-restore -n /etc/iptables.confand then create a service that loads this file on startup . Code: nano /etc/systemd/system/iptables.servicethen add this Code: [Unit]
Description=Restore iptables firewall rules
Before=network-pre.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore -n /etc/iptables.conf
[Install]
WantedBy=multi-user.targetCode: systemctl enable iptables.service
systemctl start iptables.serviceI think I've covered most of the setup process for my install , of course you will need to configure the service to suit your individual needs and for that I turn you to there excellent documentation Jellyfin Radicale HomeAssistant Esphome Docker SimpNAS Duckdns if you have any questions or feedback for me I will help where I can and edit the tutorial based on giving accurate information . |