This commit is contained in:
Moni Ghaoui 2025-04-14 19:51:40 +02:00
parent 28dac0c412
commit 47aa1a3484
71 changed files with 3317 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.env

View file

@ -0,0 +1,213 @@
# Bastille
This is my guide for getting Bastille BSD up-and-running.
First make sure that FreeBSD is up-to-date:
*NOTE* This takes a *long* time on a Raspberry PI. Only do this if you have a lot of time on your hands!
You may be smart to `tmux` first.
```sh
tmux
```
```sh
freebsd-update fetch install
```
```sh
reboot
```
After reboot, check again:
```sh
freebsd-update install
```
Verify your version:
```sh
freebsd-version
```
## Setup
First we need to make a backup of `pf.conf`, if you already setup pf before, otherwise you can skip this step.
```sh
mv /etc/pf.conf /etc/pf.conf.backup
```
And then
```sh
bastille setup
```
This will setup the loopback interface and create a `/etc/pf.conf`.
You need to manually add the following to `/etc/pf.conf`, at the bottom, in order to allow http, https and RDP:
```
pass in inet proto tcp from any to any port { 80, 443, 3389 } flags S/SA keep state
```
Then start it:
```sh
service pf start
```
The `bastille setup` will try to configure the wrong config file and complain. We need to fix the zfs stuff manually.
And change, assuming you created a zpool named `data`.
For example (WATCH OUT, BELOW COMMAND IS DANGEROUS):
```sh
zpool create -f data /dev/ada0
```
Change bastille.conf
```sh
nvim /usr/local/etc/bastille/bastille.conf
```
```
bastille_zfs_enable="YES"
bastille_zfs_zpool="data"
```
And just in case, run the setup again:
```sh
bastille setup zfs
```
## Start
Ok, now start Bastille:
```sh
service bastille restart
```
Bootstrap:
```sh
bastille bootstrap 14.2-RELEASE update
```
## Create a container
Figure out your network card:
```sh
ifconfig
```
You don't want the loopback but your real card that connects to the internet. The KVM virtual machine has `vtnet0` and the Raspberry PI has `genet0`, the Lenovo Thinkcentre has `em0`.
```sh
# Lenovo Thinkcentre
bastille create alcatraz 14.2-RELEASE 192.168.1.201 em0
```
If you want to have exlusive packages in the jail and not share the host packages, do this:
```sh
bastille pkg alcatraz bootstrap
bastille pkg alcatraz update
```
Alternatively, you can mount the package cache:
```sh
# Optional
bastille mount alcatraz /var/cache/pkg/ /var/cache/pkg/ nullfs rw 0 0
```
I like to install my favorites since I use them quite often:
```sh
bastille pkg alcatraz install -y tmux git neovim
```
Test it:
```sh
bastille pkg alcatraz install -y apache24
bastille sysrc alcatraz apache24_enable=YES
bastille service alcatraz apache24 start
```
Now go to the ip address with your browser on another machine:
http://192.168.1.201/
You should see "It works!"
Alternatively:
```sh
curl http://192.168.1.201/
```
You should see:
```html
<html><body><h1>It works!</h1></body></html>
```
Now destroy it:
```sh
bastille stop alcatraz
bastille destroy force alcatraz
```
# Using ports
```sh
bastille create alcatraz 14.2-RELEASE 192.168.1.201 em0
bastille pkg alcatraz bootstrap
bastille pkg alcatraz update
bastille pkg alcatraz install -y git
bastille cmd alcatraz git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports
```
and then go in the console:
```sh
bastille console alcatraz
```
within the console...
```sh
export BATCH=yes
cd /usr/ports/www/apache24/ && make install clean
exit
```
enable and start it ...
```sh
bastille sysrc alcatraz apache24_enable=YES
bastille service alcatraz apache24 start
```
Test it:
```sh
curl http://192.168.1.201/
```
Destroy it:
```sh
bastille destroy force alcatraz
```

View file

@ -0,0 +1,42 @@
# Caddy
```sh
bastille create caddy 14.2-RELEASE 192.168.1.200 genet0
bastille pkg caddy bootstrap
bastille pkg caddy update
bastille pkg caddy install -y caddy
```
After installing Caddy you see some instructions. To reshow them:
```sh
bastille pkg caddy info -D caddy
```
Edit the Caddyfile:
```sh
bastille pkg caddy install -y tmux neovim
bastille console caddy
tmux
nvim /usr/local/etc/caddy/Caddyfile
```
Start the service.
```sh
bastille service caddy caddy enable
bastille service caddy caddy start
```
See the logs:
```sh
bastille cmd caddy cat /var/log/caddy/caddy.log
```
To quickly look at the caddyfile:
```sh
bastille cmd caddy cat /usr/local/etc/caddy/Caddyfile
```

View file

@ -0,0 +1,31 @@
# MariaDB
```sh
bastille pkg alcatraz install -y mariadb114-server mariadb114-client
```
Repeat the message:
```sh
bastille pkg alcatraz info -D mariadb114-server
```
Enable and start
```sh
bastille sysrc alcatraz mysql_enable=YES
bastille service alcatraz mysql-server start
```
Create nextcloud database and user
```sh
bastille cmd alcatraz mysql
```
```sql
CREATE DATABASE nextcloud;
CREATE USER 'nextcloud'@'192.168.1.201' IDENTIFIED BY '1234sys!';
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'192.168.1.201';
FLUSH PRIVILEGES;
```

View file

@ -0,0 +1,73 @@
# Nextcloud
My standard setup:
```sh
bastille create alcatraz 14.2-RELEASE 192.168.1.201 em0
bastille mount alcatraz /var/cache/pkg/ /var/cache/pkg/ nullfs rw 0 0
bastille pkg alcatraz install -y tmux git neovim sudo
```
## Trying it my way
```sh
bastille pkg alcatraz install -y php83 nextcloud-php83 php83-pecl-APCu php83-extensions sd nginx
```
Repeat the message:
```sh
bastille pkg alcatraz info -D www/nextcloud
```
Additional:
```sh
bastille cmd alcatraz cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
bastille cmd alcatraz sd 'memory_limit = 128M' 'memory_limit = -1' /usr/local/etc/php.ini
```
We need to go in and out of the console for this one:
```sh
bastille console alcatraz
echo 'apc.enable_cli = 1' >> /usr/local/etc/php.ini
exit
```
Follow the instructions for [MariaDB](../MariaDB.md).
Now run the installer
```sh
bastille cmd alcatraz sudo -u www php /usr/local/www/nextcloud/occ maintenance:install \
--database='mysql' --database-host='127.0.0.1' --database-name='nextcloud' \
--database-user='nextcloud' --database-pass='1234sys!' \
--admin-user='admin' --admin-pass='1234sys!'
```
You should see:
```
[alcatraz]:
Nextcloud was successfully installed
[alcatraz]: 0
```
Edit nginx.conf for nextcloud.
```sh
bastille cmd alcatraz nvim /usr/local/etc/nginx/nginx.conf
```
Use [this file](./nginx.conf).
It's based on: https://docs.nextcloud.com/server/stable/admin_manual/installation/nginx.html#nextcloud-in-the-webroot-of-nginx
```sh
bastille service alcatraz php_fpm enable
bastille service alcatraz php_fpm start
bastille service alcatraz nginx enable
bastille service alcatraz nginx start
```

View file

@ -0,0 +1,265 @@
#user nobody;
worker_processes 1;
# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log /var/log/nginx/error.log;
#
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream php-handler {
server 127.0.0.1:9000;
#server unix:/var/run/php/php7.4-fpm.sock;
}
# Set the `immutable` cache control options only for assets with a cache busting `v` argument
map $arg_v $asset_immutable {
"" "";
default ", immutable";
}
# server {
# listen 80;
# listen [::]:80;
# server_name cloud.example.com;
# # enforce https
# return 301 https://$server_name:443$request_uri;
# }
server {
#listen 80;
#listen [::]:80;
server_name 192.168.1.201;
# Path to the root of your installation
root /usr/local/www/nextcloud;
# Use Mozilla's guidelines for SSL/TLS settings
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
#ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
#ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;
# Prevent nginx HTTP Server Detection
server_tokens off;
# HSTS settings
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
# set max upload size and increase upload timeout:
client_max_body_size 512M;
client_body_timeout 300s;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# Pagespeed is not supported by Nextcloud, so if your server is built
# with the `ngx_pagespeed` module, uncomment this line to disable it.
#pagespeed off;
# The settings allows you to optimize the HTTP2 bandwidth.
# See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/
# for tuning hints
client_body_buffer_size 512k;
# HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
# Set .mjs and .wasm MIME types
# Either include it in the default mime.types list
# and include that list explicitly or add the file extension
# only for Nextcloud like below:
include mime.types;
types {
text/javascript mjs;
application/wasm wasm;
}
# Specify how to handle directories -- specifying `/index.php$request_uri`
# here as the fallback means that Nginx always exhibits the desired behaviour
# when a client requests a path that corresponds to a directory that exists
# on the server. In particular, if that directory contains an index.php file,
# that file is correctly served; if it doesn't, then the request is passed to
# the front-end controller. This consistent behaviour means that we don't need
# to specify custom rules for certain paths (e.g. images and other assets,
# `/updater`, `/ocs-provider`), and thus
# `try_files $uri $uri/ /index.php$request_uri`
# always provides the desired behaviour.
index index.php index.html /index.php$request_uri;
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
location = / {
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Make a regex exception for `/.well-known` so that clients can still
# access it despite the existence of the regex rule
# `location ~ /(\.|autotest|...)` which would otherwise handle requests
# for `/.well-known`.
location ^~ /.well-known {
# The rules in this block are an adaptation of the rules
# in `.htaccess` that concern `/.well-known`.
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
# Let Nextcloud's API for `/.well-known` URIs handle all other
# requests by passing them to the front-end controller.
return 301 /index.php$request_uri;
}
# Rules borrowed from `.htaccess` to hide certain paths from clients
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
# Ensure this block, which passes PHP files to the PHP process, is above the blocks
# which handle static assets (as seen below). If this block is not declared first,
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
# to the URI, resulting in a HTTP 500 error response.
location ~ \.php(?:$|/) {
# Required for legacy support
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
fastcgi_param front_controller_active true; # Enable pretty urls
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_max_temp_file_size 0;
}
# Serve static files
location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ {
try_files $uri /index.php$request_uri;
# HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Cache-Control "public, max-age=15778463$asset_immutable";
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
access_log off; # Optional: Don't log access to assets
}
location ~ \.(otf|woff2?)$ {
try_files $uri /index.php$request_uri;
expires 7d; # Cache-Control policy borrowed from `.htaccess`
access_log off; # Optional: Don't log access to assets
}
# Rule borrowed from `.htaccess`
location /remote {
return 301 /remote.php$request_uri;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}

View file

@ -0,0 +1,54 @@
# Postgres
```sh
bastille create postgresql 14.2-RELEASE 192.168.1.203 em0
bastille config postgresql set allow.sysvipc=1
bastille restart postgresql
bastille pkg postgresql bootstrap
bastille pkg postgresql update
bastille pkg postgresql install -y postgresql15-server postgresql15-client
bastille service postgresql postgresql enable
bastille service postgresql postgresql initdb
bastille service postgresql postgresql start
```
You need to change `/var/db/postgres/data15/postgresql.conf`
```sh
nvim /var/db/postgres/data15/postgresql.conf
```
To listen to the ip address:
```
listen_addresses = '192.168.1.203'
```
And restart.
We need to allow communications via the jails. Add this to pf.conf on the host:
```
pass in on $ext_if proto tcp from 192.168.1.202 to 192.168.1.203 port 5432
pass out on $ext_if proto tcp from 192.168.1.203 to 192.168.1.202 port 5432
```
Add a user, for example nextcloud:
```sh
su - postgres
createuser nextcloud
createdb nextcloud -O admin
psql nextcloud
alter role nextcloud with encrypted password 'yourpassword';
grant all privileges on database nextcloud to nextcloud;
exit
exit
```
Add this to `/var/db/postgres/data15/pg_hba.conf`
```
host nextcloud nextcloud 0.0.0.0/0 scram-sha-256
host nextcloud nextcloud ::/0 scram-sha-256
```

View file

@ -0,0 +1,10 @@
# nginx
```sh
bastille create nginx 14.2-RELEASE 192.168.1.200 genet0
bastille pkg nginx bootstrap
bastille pkg nginx update
bastille pkg nginx install -y nginx
bastille service nginx nginx enable
bastille service nginx nginx start
```

View file

@ -0,0 +1,13 @@
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
# user: 1004:1004
ports:
- 13378:80
volumes:
- /home/audiobookshelf/audiobookshelf/audiobooks:/audiobooks
- /home/audiobookshelf/audiobookshelf/podcasts:/podcasts
- /home/audiobookshelf/audiobookshelf/config:/config
- /home/audiobookshelf/audiobookshelf/metadata:/metadata
environment:
- TZ=Europe/Amsterdam

View file

@ -0,0 +1,9 @@
services:
httpd:
image: httpd
restart: always
ports:
- 8081:80
# volumes:
# - ./www:/usr/local/apache2/htdocs

View file

@ -0,0 +1,8 @@
<html>
<head>
<title>Hello world!</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

View file

@ -0,0 +1,84 @@
# You need to get the example .env file:
# wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
extends:
file: hwaccel.transcoding.yml
service: quicksync # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
- /home/immich/external/:/external
env_file:
- .env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
# file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1;
Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
--command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
echo "checksum failure count is $$Chksum";
[ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: >-
postgres
-c shared_preload_libraries=vectors.so
-c 'search_path="$$user", public, vectors'
-c logging_collector=on
-c max_wal_size=2GB
-c shared_buffers=512MB
-c wal_compression=on
restart: always
volumes:
model-cache:

View file

@ -0,0 +1,54 @@
# Configurations for hardware-accelerated transcoding
# If using Unraid or another platform that doesn't allow multiple Compose files,
# you can inline the config for a backend by copying its contents
# into the immich-microservices service in the docker-compose.yml file.
# See https://immich.app/docs/features/hardware-transcoding for more info on using hardware transcoding.
services:
cpu: {}
nvenc:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities:
- gpu
- compute
- video
quicksync:
devices:
- /dev/dri:/dev/dri
rkmpp:
security_opt: # enables full access to /sys and /proc, still far better than privileged: true
- systempaths=unconfined
- apparmor=unconfined
group_add:
- video
devices:
- /dev/rga:/dev/rga
- /dev/dri:/dev/dri
- /dev/dma_heap:/dev/dma_heap
- /dev/mpp_service:/dev/mpp_service
#- /dev/mali0:/dev/mali0 # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
volumes:
#- /etc/OpenCL:/etc/OpenCL:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
#- /usr/lib/aarch64-linux-gnu/libmali.so.1:/usr/lib/aarch64-linux-gnu/libmali.so.1:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
vaapi:
devices:
- /dev/dri:/dev/dri
vaapi-wsl: # use this for VAAPI if you're running Immich in WSL2
devices:
- /dev/dri:/dev/dri
volumes:
- /usr/lib/wsl:/usr/lib/wsl
environment:
- LIBVA_DRIVER_NAME=d3d12

View file

@ -0,0 +1,30 @@
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
user: 1003:1003
network_mode: 'host'
volumes:
- /home/jellyfin/jellyfin/config:/config
- /home/jellyfin/jellyfin/cache:/cache
- type: bind
source: /home/jellyfin/jellyfin/media
target: /media
# - type: bind
# source: /path/to/media2
# target: /media2
# read_only: true
# Optional - extra fonts to be used during transcoding with subtitle burn-in
# - type: bind
# source: /path/to/fonts
# target: /usr/local/share/fonts/custom
# read_only: true
restart: 'unless-stopped'
# Optional - alternative address used for autodiscovery
# environment:
# - JELLYFIN_PublishedServerUrl=http://example.com
# Optional - may be necessary for docker healthcheck to pass if running in host network mode
# extra_hosts:
# - 'host.docker.internal:host-gateway'
devices:
- "/dev/dri:/dev/dri" # Intel QSV

View file

@ -0,0 +1,3 @@
infra/nginx-proxy-manager_data/
infra/portainer_data/
lemmy/volumes/

View file

@ -0,0 +1,55 @@
# multitenant
## nginx-proxy-manager
```sh
docker network create infra
```
Admin: http://127.0.0.1:81/
```
admin@example.com
changeme
```
## Wordpress
We need to add domain names in our `/etc/hosts` file:
```
127.0.0.1 moni0.codecompost.nl
127.0.0.1 moni1.codecompost.nl
```
And pass a project name to the docker-compose command:
```
docker-compose -p moni0 up --build --force-recreate -d
```
This will prepend `moni0_` to the containers (and add a `_1` apparently)
```
Creating network "moni0_internal_network" with the default driver
Creating volume "moni0_wordpress" with default driver
Creating volume "moni0_db" with default driver
Creating moni0_db_1 ... done
Creating moni0_wordpress_1 ... done
```
In the Nginx Proxy Manager, we can add the proxy host:
![moni0 wordpress proxy host](moni0_proxy_host.png)
We can go ahead and start a second wordpress with:
```
docker-compose -p moni1 up --build --force-recreate -d
```
And then you can configure it like this:
![Alt text](moni1_proxy_host.png)
Make sure that `moni1.codecompost.nl` is also in your hosts file, otherwise it won't work!

View file

@ -0,0 +1,31 @@
version: '3.8'
services:
nginx-proxy-manager:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./nginx-proxy-manager_data/data:/data
- ./nginx-proxy-manager_data/letsencrypt:/etc/letsencrypt
networks:
- infra
# portainer:
# image: 'portainer/portainer-ce:latest'
# restart: always
# ports:
# - '8000:8000'
# - '9443:9443'
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock
# - ./portainer_data:/data
# networks:
# - infra
networks:
infra:
external: true

View file

@ -0,0 +1,12 @@
podman run \
--detach \
--label "io.containers.autoupdate=registry" \
--name jellyfin \
--publish 8096:8096/tcp \
--rm \
--user $(id -u):$(id -g) \
--userns keep-id \
--volume jellyfin-cache:/cache:Z \
--volume jellyfin-config:/config:Z \
--mount type=bind,source=/home/moni/media/,destination=/media,ro=true,relabel=private \
docker.io/jellyfin/jellyfin:latest

View file

@ -0,0 +1,30 @@
# DB Version: 15
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 8 GB
# CPUs num: 4
# Data Storage: ssd
max_connections = 200
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
checkpoint_completion_target = 0.9
checkpoint_timeout = 86400
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 5242kB
min_wal_size = 1GB
max_wal_size = 30GB
max_worker_processes = 4
max_parallel_workers_per_gather = 2
max_parallel_workers = 4
max_parallel_maintenance_workers = 2
# Other custom params
temp_file_size=1GB
synchronous_commit=off
# This one shouldn't be on regularly, because DB migrations often take a long time
# statement_timeout = 10000

View file

@ -0,0 +1,114 @@
version: "3.7"
x-logging: &default-logging
driver: "json-file"
options:
max-size: "50m"
max-file: "4"
services:
proxy:
image: nginx:1-alpine
# ports:
# # actual and only port facing any connection from outside
# # Note, change the left number if port 1236 is already in use on your system
# # You could use port 80 if you won't use a reverse proxy
# - "1236:8536"
volumes:
- ./nginx_internal.conf:/etc/nginx/nginx.conf:ro,Z
restart: always
logging: *default-logging
depends_on:
- pictrs
- lemmy-ui
networks:
- lemmy-internal
- infra
lemmy:
image: dessalines/lemmy:latest
hostname: lemmy
restart: always
logging: *default-logging
environment:
- RUST_LOG="warn"
- LEMMY_CORS_ORIGIN=http://lemmy.codecompost.nl
volumes:
- ./lemmy.hjson:/config/config.hjson:Z
depends_on:
- postgres
- pictrs
networks:
- lemmy-internal
lemmy-ui:
image: dessalines/lemmy-ui:latest
environment:
- LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536
- LEMMY_UI_LEMMY_EXTERNAL_HOST=lemmy.codecompost.nl
- LEMMY_UI_HTTPS=true
volumes:
- ./volumes/lemmy-ui/extra_themes:/app/extra_themes
depends_on:
- lemmy
restart: always
logging: *default-logging
networks:
- lemmy-internal
pictrs:
image: asonix/pictrs:0.4.0-rc.7
# this needs to match the pictrs url in lemmy.hjson
hostname: pictrs
# we can set options to pictrs like this, here we set max. image size and forced format for conversion
# entrypoint: /sbin/tini -- /usr/local/bin/pict-rs -p /mnt -m 4 --image-format webp
environment:
- PICTRS_OPENTELEMETRY_URL=http://otel:4137
- PICTRS__API_KEY=JmT3cMDL252EJw
- RUST_LOG=debug
- RUST_BACKTRACE=full
- PICTRS__MEDIA__VIDEO_CODEC=vp9
- PICTRS__MEDIA__GIF__MAX_WIDTH=256
- PICTRS__MEDIA__GIF__MAX_HEIGHT=256
- PICTRS__MEDIA__GIF__MAX_AREA=65536
- PICTRS__MEDIA__GIF__MAX_FRAME_COUNT=400
user: 991:991
volumes:
- ./volumes/pictrs:/mnt:Z
restart: always
logging: *default-logging
deploy:
resources:
limits:
memory: 690m
networks:
- lemmy-internal
postgres:
image: postgres:15-alpine
hostname: postgres
environment:
- POSTGRES_USER=lemmy
- POSTGRES_PASSWORD=JmT3cMDL252EJw
- POSTGRES_DB=lemmy
volumes:
- ./volumes/postgres:/var/lib/postgresql/data:Z
- ./customPostgresql.conf:/etc/postgresql.conf
restart: always
logging: *default-logging
networks:
- lemmy-internal
postfix:
image: mwader/postfix-relay
environment:
- POSTFIX_myhostname=codecompost.nl
restart: "always"
logging: *default-logging
networks:
- lemmy-internal
networks:
lemmy-internal:
infra:
external: true

View file

@ -0,0 +1,19 @@
{
# for more info about the config, check out the documentation
# https://join-lemmy.org/docs/en/administration/configuration.html
database: {
host: postgres
password: "JmT3cMDL252EJw"
}
hostname: "lemmy.codecompost.nl"
pictrs: {
url: "http://pictrs:8080/"
api_key: "JmT3cMDL252EJw"
}
email: {
smtp_server: "postfix:25"
smtp_from_address: "noreply@codecompost.nl"
tls_type: "none"
}
}

View file

@ -0,0 +1,96 @@
worker_processes auto;
events {
worker_connections 1024;
}
http {
# We construct a string consistent of the "request method" and "http accept header"
# and then apply soem ~simply regexp matches to that combination to decide on the
# HTTP upstream we should proxy the request to.
#
# Example strings:
#
# "GET:application/activity+json"
# "GET:text/html"
# "POST:application/activity+json"
#
# You can see some basic match tests in this regex101 matching this configuration
# https://regex101.com/r/vwMJNc/1
#
# Learn more about nginx maps here http://nginx.org/en/docs/http/ngx_http_map_module.html
map "$request_method:$http_accept" $proxpass {
# If no explicit matches exists below, send traffic to lemmy-ui
default "http://lemmy-ui";
# GET/HEAD requests that accepts ActivityPub or Linked Data JSON should go to lemmy.
#
# These requests are used by Mastodon and other fediverse instances to look up profile information,
# discover site information and so on.
"~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy";
# All non-GET/HEAD requests should go to lemmy
#
# Rather than calling out POST, PUT, DELETE, PATCH, CONNECT and all the verbs manually
# we simply negate the GET|HEAD pattern from above and accept all possibly $http_accept values
"~^(?!(GET|HEAD)).*:" "http://lemmy";
}
upstream lemmy {
# this needs to map to the lemmy (server) docker service hostname
server "lemmy:8536";
}
upstream lemmy-ui {
# this needs to map to the lemmy-ui docker service hostname
server "lemmy-ui:1234";
}
server {
# this is the port inside docker, not the public one yet
listen 1236;
listen 8536;
# change if needed, this is facing the public web
server_name localhost;
server_tokens off;
gzip on;
gzip_types text/css application/javascript image/svg+xml;
gzip_vary on;
# Upload limit, relevant for pictrs
client_max_body_size 20M;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# frontend general requests
location / {
proxy_pass $proxpass;
rewrite ^(.+)/+$ $1 permanent;
# Send actual client IP upstream
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# backend
location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) {
proxy_pass "http://lemmy";
# proxy common stuff
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Send actual client IP upstream
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}

View file

@ -0,0 +1,28 @@
# Generated with mastodon:setup on 2023-07-06 02:48:24 UTC
# Some variables in this file will be interpreted differently whether you are
# using docker-compose or not.
LOCAL_DOMAIN=mastodon.codecompost.nl
SINGLE_USER_MODE=true
SECRET_KEY_BASE=2f845c9336267ad5ddf79ca900d3940990c0a8010c7c3a5321d5cda8e5b9ac32ebcc75ea67396977bb65c7c970f71d123312cd180c6a1e7b12e608eee3d63e27
OTP_SECRET=e8c4370e30704c85552fd48d766c859323ebd28aaaffa8a9943687b2ac925610eeba1bc9b3a472ae1b684862e7d02ea7d5b69a02624d395626b0cd9fef4aeb2c
VAPID_PRIVATE_KEY=fHCAaeeQ_HxQBKvw9jzVrTxO9mpoup46luhPmKZsRhI=
VAPID_PUBLIC_KEY=BKkmTVZwiL4hmqYt91AsWvB4DS38MnFygDumi9jCqjSw3IClXA5WhxCQnYSpGzOKvvrN-Lgy4Fm2Rx5CPhmelS0=
DB_HOST=moni-mastodon-db-1
DB_PORT=5432
DB_NAME=mastodon
DB_USER=mastodon
DB_PASS=mastodon
REDIS_HOST=moni-mastodon-redis-1
REDIS_PORT=6379
REDIS_PASSWORD=
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS=auto
SMTP_FROM_ADDRESS=Mastodon <notifications@mastodon.codecompost.nl>
LOCAL_HTTPS=false

View file

@ -0,0 +1,137 @@
version: '3'
services:
db:
restart: always
image: postgres:14-alpine
shm_size: 256mb
networks:
- internal_network
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'postgres']
volumes:
- postgres14:/var/lib/postgresql/data
environment:
- POSTGRES_USER=mastodon
- POSTGRES_PASSWORD=mastodon
redis:
restart: always
image: redis:7-alpine
networks:
- internal_network
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
volumes:
- redis:/data
# es:
# restart: always
# image: docker.elastic.co/elasticsearch/elasticsearch:7.17.4
# environment:
# - "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
# - "xpack.license.self_generated.type=basic"
# - "xpack.security.enabled=false"
# - "xpack.watcher.enabled=false"
# - "xpack.graph.enabled=false"
# - "xpack.ml.enabled=false"
# - "bootstrap.memory_lock=true"
# - "cluster.name=es-mastodon"
# - "discovery.type=single-node"
# - "thread_pool.write.queue_size=1000"
# networks:
# - infra
# - internal_network
# healthcheck:
# test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
# volumes:
# - ./elasticsearch:/usr/share/elasticsearch/data
# ulimits:
# memlock:
# soft: -1
# hard: -1
# nofile:
# soft: 65536
# hard: 65536
# ports:
# - '127.0.0.1:9200:9200'
web:
image: ghcr.io/mastodon/mastodon
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
networks:
- infra
- internal_network
healthcheck:
# prettier-ignore
test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1']
# ports:
# - '127.0.0.1:3000:3000'
depends_on:
- db
- redis
# - es
volumes:
- public_system:/mastodon/public/system
streaming:
image: ghcr.io/mastodon/mastodon
restart: always
env_file: .env.production
command: node ./streaming
networks:
- infra
- internal_network
healthcheck:
# prettier-ignore
test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1']
# ports:
# - '127.0.0.1:4000:4000'
depends_on:
- db
- redis
sidekiq:
image: ghcr.io/mastodon/mastodon
restart: always
env_file: .env.production
command: bundle exec sidekiq
depends_on:
- db
- redis
networks:
- infra
- internal_network
volumes:
- public_system:/mastodon/public/system
healthcheck:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
## Uncomment to enable federation with tor instances along with adding the following ENV variables
## http_proxy=http://privoxy:8118
## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
# tor:
# image: sirboops/tor
# networks:
# - infra
# - internal_network
#
# privoxy:
# image: sirboops/privoxy
# volumes:
# - ./priv-config:/opt/config
# networks:
# - infra
# - internal_network
networks:
infra:
external: true
internal_network:
volumes:
postgres14:
redis:
public_system:

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -0,0 +1,2 @@
https://github.com/nextcloud/all-in-one

View file

@ -0,0 +1,17 @@
services:
nextcloud-aio-mastercontainer:
image: nextcloud/all-in-one:latest
init: true
restart: always
container_name: nextcloud-aio-mastercontainer # This line is not allowed to be changed as otherwise AIO will not work correctly
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # This line is not allowed to be changed as otherwise the built-in backup solution will not work
- /var/run/docker.sock:/var/run/docker.sock:ro # May be changed on macOS, Windows or docker rootless. See the applicable documentation. If adjusting, don't forget to also set 'WATCHTOWER_DOCKER_SOCKET_PATH'!
ports:
- 80:80 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
- 8080:8080
- 8443:8443
volumes: # If you want to store the data on a different drive, see https://github.com/nextcloud/all-in-one#how-to-store-the-filesinstallation-on-a-separate-drive
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer # This line is not allowed to be changed as otherwise the built-in backup solution will not work

View file

@ -0,0 +1,12 @@
version: '2'
services:
moni8080:
image: httpd
networks:
- npm
volumes:
- /home/moni/sites/moni8080:/usr/local/apache2/htdocs/
networks:
npm:
external: true

View file

@ -0,0 +1,8 @@
<html>
<head>
Moni 8080
</head>
<body>
This is MONI 8080
</body>
</html>

View file

@ -0,0 +1,12 @@
version: '2'
services:
moni8081:
image: httpd
networks:
- npm
volumes:
- /home/moni/sites/moni8081:/usr/local/apache2/htdocs/
networks:
npm:
external: true

View file

@ -0,0 +1,8 @@
<html>
<head>
Moni 8081
</head>
<body>
This is MONI 8081
</body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head>
Moni 8082
</head>
<body>
This is MONI 8082
</body>
</html>

View file

@ -0,0 +1,7 @@
# Not the latest version to be able to test updates
FROM wordpress:6.0.0
WORKDIR /usr/src/wordpress
RUN set -eux; \
find /etc/apache2 -name '*.conf' -type f -exec sed -ri -e "s!/var/www/html!$PWD!g" -e "s!Directory /var/www/!Directory $PWD!g" '{}' +; \
cp -s wp-config-docker.php wp-config.php
RUN echo "define('FS_METHOD','direct');" >> wp-config.php

View file

@ -0,0 +1,43 @@
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
# ports:
# - 8080:80
depends_on:
- db
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
networks:
- infra
- internal_network
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
networks:
- internal_network
volumes:
wordpress:
db:
networks:
infra:
external: true
internal_network:

View file

@ -0,0 +1,40 @@
# Disabling SSL
```sh
docker exec -it nextcloud-aio-mastercontainer bash
```
in the container:
```sh
vi /etc/apache2/sites-available/mastercontainer.conf
```
Change the line to disable SSL:
```
SSLEngine off
```
Restart https *within the container*:
```sh
killall httpd
/usr/sbin/httpd
```
You can exit after that.
# Run OCC command
```sh
docker exec -it --user www-data nextcloud-aio-nextcloud /var/www/html/occ
```
# Brute force protection
To add the Caddy Jails container that is running on `192.168.1.200` to the trusted proxies list:
```sh
docker exec --user www-data -it nextcloud-aio-nextcloud php occ config:system:set trusted_proxies 2 --value="192.168.1.200"
```

View file

@ -0,0 +1,67 @@
services:
nextcloud-aio-mastercontainer:
image: nextcloud/all-in-one:latest
init: true
restart: always
container_name: nextcloud-aio-mastercontainer # This line is not allowed to be changed as otherwise AIO will not work correctly
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # This line is not allowed to be changed as otherwise the built-in backup solution will not work
- /var/run/docker.sock:/var/run/docker.sock:ro # May be changed on macOS, Windows or docker rootless. See the applicable documentation. If adjusting, don't forget to also set 'WATCHTOWER_DOCKER_SOCKET_PATH'!
ports:
# - 80:80 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
- 8080:8080
# - 8443:8443 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
environment: # Is needed when using any of the options below
# AIO_DISABLE_BACKUP_SECTION: false # Setting this to true allows to hide the backup section in the AIO interface. See https://github.com/nextcloud/all-in-one#how-to-disable-the-backup-section
APACHE_PORT: 11000 # Is needed when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
APACHE_IP_BINDING: 0.0.0.0 # Should be set when running behind a web server or reverse proxy (like Apache, Nginx, Cloudflare Tunnel and else) that is running on the same host. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
SKIP_DOMAIN_VALIDATION: true
ALLOW_INSECURE_ACCESS: true
# BORG_RETENTION_POLICY: --keep-within=7d --keep-weekly=4 --keep-monthly=6 # Allows to adjust borgs retention policy. See https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy
# COLLABORA_SECCOMP_DISABLED: false # Setting this to true allows to disable Collabora's Seccomp feature. See https://github.com/nextcloud/all-in-one#how-to-disable-collaboras-seccomp-feature
NEXTCLOUD_DATADIR: /home/nextcloud/nextcloud-data # Allows to set the host directory for Nextcloud's datadir. ⚠️⚠️⚠️ Warning: do not set or adjust this value after the initial Nextcloud installation is done! See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir
# NEXTCLOUD_MOUNT: /mnt/ # Allows the Nextcloud container to access the chosen directory on the host. See https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host
# NEXTCLOUD_UPLOAD_LIMIT: 10G # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud
# NEXTCLOUD_MAX_TIME: 3600 # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud
# NEXTCLOUD_MEMORY_LIMIT: 512M # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud
# NEXTCLOUD_TRUSTED_CACERTS_DIR: /path/to/my/cacerts # CA certificates in this directory will be trusted by the OS of the nexcloud container (Useful e.g. for LDAPS) See See https://github.com/nextcloud/all-in-one#how-to-trust-user-defined-certification-authorities-ca
# NEXTCLOUD_STARTUP_APPS: deck twofactor_totp tasks calendar contacts notes # Allows to modify the Nextcloud apps that are installed on starting AIO the first time. See https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup
# NEXTCLOUD_ADDITIONAL_APKS: imagemagick # This allows to add additional packages to the Nextcloud container permanently. Default is imagemagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-os-packages-permanently-to-the-nextcloud-container
# NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # This allows to add additional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container
NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device in the Nextcloud container. ⚠️⚠️⚠️ Warning: this only works if the '/dev/dri' device is present on the host! If it should not exist on your host, don't set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud
# NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps
# TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port
# WATCHTOWER_DOCKER_SOCKET_PATH: /var/run/docker.sock # Needs to be specified if the docker socket on the host is not located in the default '/var/run/docker.sock'. Otherwise mastercontainer updates will fail. For macos it needs to be '/var/run/docker.sock'
# networks: # Is needed when you want to create the nextcloud-aio network with ipv6-support using this file, see the network config at the bottom of the file
# - nextcloud-aio # Is needed when you want to create the nextcloud-aio network with ipv6-support using this file, see the network config at the bottom of the file
# security_opt: ["label:disable"] # Is needed when using SELinux
# # Optional: Caddy reverse proxy. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md
# # You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588
# caddy:
# image: caddy:alpine
# restart: always
# container_name: caddy
# volumes:
# - ./Caddyfile:/etc/caddy/Caddyfile
# - ./certs:/certs
# - ./config:/config
# - ./data:/data
# - ./sites:/srv
# network_mode: "host"
volumes: # If you want to store the data on a different drive, see https://github.com/nextcloud/all-in-one#how-to-store-the-filesinstallation-on-a-separate-drive
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer # This line is not allowed to be changed as otherwise the built-in backup solution will not work
# # Optional: If you need ipv6, follow step 1 and 2 of https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md first and then uncomment the below config in order to activate ipv6 for the internal nextcloud-aio network.
# # Please make sure to uncomment also the networking lines of the mastercontainer above in order to actually create the network with docker-compose
# networks:
# nextcloud-aio:
# name: nextcloud-aio # This line is not allowed to be changed as otherwise the created network will not be used by the other containers of AIO
# driver: bridge
# enable_ipv6: true
# ipam:
# driver: default
# config:
# - subnet: fd12:3456:789a:2::/64 # IPv6 subnet to use

View file

@ -0,0 +1,13 @@
docker stop nextcloud-aio-apache && docker start nextcloud-aio-apache
docker stop nextcloud-aio-notify-push && docker start nextcloud-aio-notify-push
docker stop nextcloud-aio-nextcloud && docker start nextcloud-aio-nextcloud
# docker stop nextcloud-aio-docker-socket-proxy && docker start nextcloud-aio-docker-socket-proxy
docker stop nextcloud-aio-imaginary && docker start nextcloud-aio-imaginary
# docker stop nextcloud-aio-fulltextsearch && docker start nextcloud-aio-fulltextsearch
# docker stop nextcloud-aio-clamav && docker start nextcloud-aio-clamav
docker stop nextcloud-aio-redis && docker start nextcloud-aio-redis
docker stop nextcloud-aio-database && docker start nextcloud-aio-database
docker stop nextcloud-aio-talk && docker start nextcloud-aio-talk
docker stop nextcloud-aio-collabora && docker start nextcloud-aio-collabora
# docker stop nextcloud-aio-domaincheck # && docker start nextcloud-aio-domaincheck
# docker stop nextcloud-aio-mastercontainer && docker start nextcloud-aio-mastercontainer

View file

@ -0,0 +1,13 @@
docker stop nextcloud-aio-apache
docker stop nextcloud-aio-notify-push
docker stop nextcloud-aio-nextcloud
# docker stop nextcloud-aio-docker-socket-proxy
docker stop nextcloud-aio-imaginary
# docker stop nextcloud-aio-fulltextsearch
# docker stop nextcloud-aio-clamav
docker stop nextcloud-aio-redis
docker stop nextcloud-aio-database
docker stop nextcloud-aio-talk
docker stop nextcloud-aio-collabora
# docker stop nextcloud-aio-domaincheck
# docker stop nextcloud-aio-mastercontainer

View file

@ -0,0 +1,3 @@
```sh
docker compose exec photoprism photoprism --help
```

View file

@ -0,0 +1,152 @@
# Example Docker Compose config file for PhotoPrism (Linux / AMD64)
#
# Note:
# - Running PhotoPrism on a server with less than 4 GB of swap space or setting a memory/swap limit can cause unexpected
# restarts ("crashes"), for example, when the indexer temporarily needs more memory to process large files.
# - If you install PhotoPrism on a public server outside your home network, please always run it behind a secure
# HTTPS reverse proxy such as Traefik or Caddy. Your files and passwords will otherwise be transmitted
# in clear text and can be intercepted by anyone, including your provider, hackers, and governments:
# https://docs.photoprism.app/getting-started/proxies/traefik/
#
# Setup Guides:
# - https://docs.photoprism.app/getting-started/docker-compose/
# - https://docs.photoprism.app/getting-started/raspberry-pi/
# - https://www.photoprism.app/kb/activation
#
# Troubleshooting Checklists:
# - https://docs.photoprism.app/getting-started/troubleshooting/
# - https://docs.photoprism.app/getting-started/troubleshooting/docker/
# - https://docs.photoprism.app/getting-started/troubleshooting/mariadb/
#
# CLI Commands:
# - https://docs.photoprism.app/getting-started/docker-compose/#command-line-interface
#
# All commands may have to be prefixed with "sudo" when not running as root.
# This will point the home directory shortcut ~ to /root in volume mounts.
services:
photoprism:
## Use photoprism/photoprism:preview for testing preview builds:
image: photoprism/photoprism:latest
## Don't enable automatic restarts until PhotoPrism has been properly configured and tested!
## If the service gets stuck in a restart loop, this points to a memory, filesystem, network, or database issue:
## https://docs.photoprism.app/getting-started/troubleshooting/#fatal-server-errors
# restart: unless-stopped
stop_grace_period: 10s
depends_on:
- mariadb
security_opt:
- seccomp:unconfined
- apparmor:unconfined
## Server port mapping in the format "Host:Container". To use a different port, change the host port on
## the left-hand side and keep the container port, e.g. "80:2342" (for HTTP) or "443:2342 (for HTTPS):
ports:
- "2342:2342"
## Before you start the service, please check the following config options (and change them as needed):
## https://docs.photoprism.app/getting-started/config-options/
environment:
PHOTOPRISM_ADMIN_USER: "admin" # admin login username
PHOTOPRISM_ADMIN_PASSWORD: "5bp3ptdBGM173t" # initial admin password (8-72 characters)
PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
PHOTOPRISM_SITE_URL: "http://localhost:2342/" # server URL in the format "http(s)://domain.name(:port)/(path)"
PHOTOPRISM_DISABLE_TLS: "false" # disables HTTPS/TLS even if the site URL starts with https:// and a certificate is available
PHOTOPRISM_DEFAULT_TLS: "true" # defaults to a self-signed HTTPS/TLS certificate if no other certificate is available
PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video)
PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip)
PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic
PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality)
PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features
PHOTOPRISM_DISABLE_CHOWN: "false" # disables updating storage permissions via chmod and chown on startup
PHOTOPRISM_DISABLE_WEBDAV: "false" # disables built-in WebDAV server
PHOTOPRISM_DISABLE_SETTINGS: "false" # disables settings UI and API
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
PHOTOPRISM_DISABLE_FACES: "false" # disables face detection and recognition (requires TensorFlow)
PHOTOPRISM_DISABLE_CLASSIFICATION: "false" # disables image classification (requires TensorFlow)
PHOTOPRISM_DISABLE_VECTORS: "false" # disables vector graphics support
PHOTOPRISM_DISABLE_RAW: "false" # disables indexing and conversion of RAW images
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
PHOTOPRISM_SIDECAR_YAML: "true" # creates YAML sidecar files to back up picture metadata
PHOTOPRISM_BACKUP_ALBUMS: "true" # creates YAML files to back up album metadata
PHOTOPRISM_BACKUP_DATABASE: "true" # creates regular backups based on the configured schedule
PHOTOPRISM_BACKUP_SCHEDULE: "daily" # backup SCHEDULE in cron format (e.g. "0 12 * * *" for daily at noon) or at a random time (daily, weekly)
PHOTOPRISM_INDEX_SCHEDULE: "" # indexing SCHEDULE in cron format (e.g. "@every 3h" for every 3 hours; "" to disable)
PHOTOPRISM_AUTO_INDEX: 300 # delay before automatically indexing files in SECONDS when uploading via WebDAV (-1 to disable)
PHOTOPRISM_AUTO_IMPORT: -1 # delay before automatically importing files in SECONDS when uploading via WebDAV (-1 to disable)
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
PHOTOPRISM_UPLOAD_NSFW: "true" # allows uploads that MAY be offensive (no effect without TensorFlow)
# PHOTOPRISM_DATABASE_DRIVER: "sqlite" # SQLite is an embedded database that does not require a separate database server
PHOTOPRISM_DATABASE_DRIVER: "mysql" # MariaDB 10.5.12+ (MySQL successor) offers significantly better performance compared to SQLite
PHOTOPRISM_DATABASE_SERVER: "mariadb:3306" # MariaDB database server (hostname:port)
PHOTOPRISM_DATABASE_NAME: "photoprism" # MariaDB database schema name
PHOTOPRISM_DATABASE_USER: "photoprism" # MariaDB database user name
PHOTOPRISM_DATABASE_PASSWORD: "insecure" # MariaDB database user password
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
PHOTOPRISM_SITE_DESCRIPTION: "" # meta site description
PHOTOPRISM_SITE_AUTHOR: "" # meta site author
## Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/):
PHOTOPRISM_FFMPEG_ENCODER: "intel" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi)
# PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
# PHOTOPRISM_FFMPEG_BITRATE: "32" # video bitrate limit in Mbit/s (default: 50)
## Run/install on first startup (options: update https gpu ffmpeg tensorflow davfs clitools clean):
# PHOTOPRISM_INIT: "https gpu tensorflow"
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
# PHOTOPRISM_UID: 1000
# PHOTOPRISM_GID: 1000
# PHOTOPRISM_UMASK: 0000
## Start as non-root user before initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
# user: "1000:1000"
## Share hardware devices with FFmpeg and TensorFlow (optional):
devices:
- "/dev/dri:/dev/dri" # Intel QSV
# - "/dev/nvidia0:/dev/nvidia0" # Nvidia CUDA
# - "/dev/nvidiactl:/dev/nvidiactl"
# - "/dev/nvidia-modeset:/dev/nvidia-modeset"
# - "/dev/nvidia-nvswitchctl:/dev/nvidia-nvswitchctl"
# - "/dev/nvidia-uvm:/dev/nvidia-uvm"
# - "/dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools"
# - "/dev/video11:/dev/video11" # Video4Linux Video Encode Device (h264_v4l2m2m)
working_dir: "/photoprism" # do not change or remove
## Storage Folders: "~" is a shortcut for your home directory, "." for the current directory
volumes:
# "/host/folder:/photoprism/folder" # Example
- "/home/photoprism/Pictures:/photoprism/originals" # Original media files (DO NOT REMOVE)
# - "/example/family:/photoprism/originals/family" # *Additional* media folders can be mounted like this
- "/home/photoprism/Import:/photoprism/import" # *Optional* base folder from which files can be imported to originals
- "/home/photoprism/storage:/photoprism/storage" # *Writable* storage folder for cache, database, and sidecar files (DO NOT REMOVE)
## MariaDB Database Server (recommended)
## see https://docs.photoprism.app/getting-started/faq/#should-i-use-sqlite-mariadb-or-mysql
mariadb:
image: mariadb:11
## If MariaDB gets stuck in a restart loop, this points to a memory or filesystem issue:
## https://docs.photoprism.app/getting-started/troubleshooting/#fatal-server-errors
restart: unless-stopped
stop_grace_period: 5s
security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239
- seccomp:unconfined
- apparmor:unconfined
command: --innodb-buffer-pool-size=512M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
## Never store database files on an unreliable device such as a USB flash drive, an SD card, or a shared network folder:
volumes:
- "/home/photoprism/database:/var/lib/mysql" # DO NOT REMOVE
environment:
MARIADB_AUTO_UPGRADE: "1"
MARIADB_INITDB_SKIP_TZINFO: "1"
MARIADB_DATABASE: "photoprism"
MARIADB_USER: "photoprism"
MARIADB_PASSWORD: "insecure"
MARIADB_ROOT_PASSWORD: "insecure"
## Watchtower upgrades services automatically (optional)
## see https://docs.photoprism.app/getting-started/updates/#watchtower
## activate via "COMPOSE_PROFILES=update docker compose up -d"
watchtower:
restart: unless-stopped
image: containrrr/watchtower
profiles: ["update"]
environment:
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_POLL_INTERVAL: 7200 # checks for updates every two hours
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "~/.docker/config.json:/config.json" # optional, for authentication if you have a Docker Hub account

View file

@ -0,0 +1,31 @@
name: pinepods
services:
db:
image: postgres:latest
env_file: '.env'
volumes:
- /home/pinepods/pinepods/pgdata:/var/lib/postgresql/data
# Exposing the postgres database port is dumb.
# ports:
# - "5432:5432"
restart: always
valkey:
image: valkey/valkey:8-alpine
# Exposing a nosql database is expecially dumb.
# ports:
# - "6379:6379"
pinepods:
image: madeofpendletonwool/pinepods:latest
ports:
- "8040:8040"
env_file: '.env'
volumes:
# Mount the download and backup locations on the server
- /home/pinepods/pinepods/downloads:/opt/pinepods/downloads
- /home/pinepods/pinepods/backups:/opt/pinepods/backups
depends_on:
- db
- valkey

View file

@ -0,0 +1,42 @@
# https://github.com/nickkjolsing/dockerMullvadVPN
name: torrent
services:
openvpn-client:
image: ghcr.io/wfg/openvpn-client # Image on Docker. Shoutout to ghcr.io
container_name: openvpn-client
cap_add:
- NET_ADMIN # Needs to be here
environment:
- KILL_SWITCH=on # Turns off internet access if the VPN connection drops
- SUBNETS=192.168.0.0/24,192.168.1.0/24
devices:
- /dev/net/tun
volumes:
- /home/jellyfin/mullvad_config_linux_nl_ams:/data/vpn
ports:
- 8082:8082
- 6881:6881
- 6881:6881/udp
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
environment:
- PUID=1003
- PGID=1003
- TZ=Europe/Amsterdam
- WEBUI_PORT=8082
- TORRENTING_PORT=6881
volumes:
- /home/jellyfin/qbitorrent/appdata:/config
- /home/jellyfin/qbitorrent/downloads:/downloads #optional
- /home/jellyfin/jellyfin/media:/media
# ports:
# - 8082:8082
# - 6881:6881
# - 6881:6881/udp
network_mode: container:openvpn-client # This uses the port setting of the openvpn
restart: unless-stopped

View file

@ -0,0 +1,24 @@
services:
webtop:
image: lscr.io/linuxserver/webtop:fedora-xfce
container_name: webtop
security_opt:
- seccomp:unconfined #optional
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
- SUBFOLDER=/ #optional
- TITLE=Webtop #optional
- CUSTOM_USER=moni
- PASSWORD=Pd5oBZ3vN31wCkj8
volumes:
- /home/moni/webtop/data:/config
- /var/run/docker.sock:/var/run/docker.sock #optional
ports:
- 3000:3000
- 3001:3001
devices:
- /dev/dri:/dev/dri #optional
shm_size: "1gb" #optional
restart: unless-stopped

View file

@ -0,0 +1,18 @@
services:
windows:
image: dockurr/windows
container_name: windows
environment:
VERSION: "11"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
volumes:
- /var/win:/storage

View file

@ -0,0 +1,31 @@
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:8.0
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:

86
homeservers/Backup.md Normal file
View file

@ -0,0 +1,86 @@
# Syncthing
```sh
sudo systemctl restart syncthing@photoprism.service
```
Admin interface: http://192.168.1.10:8384/
I have a user called `photoprism` and the password is in Bitwarden
# Borg Backup to Hetzner Storage Box
For backup I use [Borg](https://borgbackup.readthedocs.io/). I followed the steps described in this community article:
* [Install and Configure BorgBackup](https://community.hetzner.com/tutorials/install-and-configure-borgbackup)
We have two backups in the storage box:
* `/./borgbackup/photoprism`
* `/./borgbackup/nextcloud`
## Photoprism backup
This is what I did for Photoprism
The init script (which is only done once, be careful it will overwrite!):
```sh
# (As root)
export BORG_RSH='ssh -i /root/.ssh/id_ed25519'
export BORG_PASSPHRASE="<I GENERATED A PASSPHRASE>"
borg init --encryption=repokey ssh://u388089@u388089.your-storagebox.de:23/./borgbackup/photoprism
```
It outputs a key which I put in Bitwarden (you need it to decrypt the backup).
To make a manual backup:
```sh
export BORG_RSH='ssh -i /root/.ssh/id_ed25519'
export BORG_PASSPHRASE="<SEE BITWARDEN>"
borg create --stats ssh://u388089@u388089.your-storagebox.de:23/./borgbackup/photoprism::2024_11_24 /home/photoprism/Import/ /home/photoprism/Pictures/
```
The above can be found in Bitwarden, look for "Hetzner Borg Backup Script for Photoprism"
I also created a bash script in `/usr/local/bin/photoprism_backup.sh` (as mentioned in the article).
You can find it here in this repo:
* [photoprism_backup.sh](./scripts/photoprism_backup.sh)
## Nextcloud backup
Ok, this is confusing but Nextcloud uses Borgbackup internally. Go to the [aio interface](http://192.168.1.10:8080/) and you'll notice there are backups to:
```
/root/nextcloudbackup
```
So nextcloud keeps making backups to this directory. Not ideal (TODO: I gotta find a solution for this).
But I can rclone the data:
```sh
rclone sync -v /root/nextcloudbackup/ hetzner:/cloned_borgbackup/nextcloud
```
For this I also created a script and placed it in `/usr/local/bin`
[nextcloud_backup.sh](./scripts/nextcloud_backup.sh)
# Automatic backup
* [cloud_backup.service](./scripts/cloud_backup.service)
* [cloud_backup.timer](./scripts/cloud_backup.timer)
```sh
cp -v cloud_backup.service /etc/systemd/system/
cp -v cloud_backup.timer /etc/systemd/system/
```
```sh
systemctl enable cloud_backup.service
systemctl enable cloud_backup.timer
```

15
homeservers/Immich.md Normal file
View file

@ -0,0 +1,15 @@
Compose file:
[compose.yaml](../containers/docker/immich/compose.yaml)
For immich I added a dedicated user:
```sh
sudo useradd immich
```
This creates a `/home/immich` directory. We neet to run `cat /etc/passwd` to get the id of the user.
Unfortunately, I have not been able to use the user id for the containers, so everything is written as root. I'm still using `/home/immich`, but all the files are written there as root.
Eventually I might use podman but I don't know enough about it yet to get comfortable with it.

21
homeservers/Jellyfin.md Normal file
View file

@ -0,0 +1,21 @@
# Jellyfin
Compose file:
* [compose.yaml](../containers/docker/jellyfin/compose.yaml)
I made a user names `jellyfin` and put its uid:guid in the compose file. All the files are in the home directory of that user `/home/jellyfin`.
The user also has the authorized_keys so I can do this:
```sh
ssh jellyfin@192.168.1.10
```
and proceed to add the directories for the media files:
```sh
cd jellyfin/media/tvshows/
mkdir "Show I Want To Watch (2020)"
mkdir "Season 01"
```

22
homeservers/Nextcloud.md Normal file
View file

@ -0,0 +1,22 @@
# Nextcloud
I have a dedicated user:
```sh
sudo useradd nextcloud
```
I'm running the Nextcloud All-In-One container. In order to make it easy I have a [stop](../containers/docker/nextcloud/stop.sh) and [restart](../containers/docker/nextcloud/stop.sh) script.
Nextcloud runs on
* https://nextcloud.allisonandmoni.online/
When you first start it up, you need to first disable the SSL from within the container:
* [Ugly hack README](../containers/docker/nextcloud/README.md)
And then go to:
* http://192.168.1.11:8080

43
homeservers/PhotoPrism.md Normal file
View file

@ -0,0 +1,43 @@
# Photoprism
What we are really running on this machine is Photoprism using this [docker-compose](../containers/docker/photoprism/docker-compose.yml) file, like this:
```sh
cd ~/projects/stuff/containers/docker/photoprism
docker compose up --detach
```
To stop it:
```sh
docker compose down
```
To update it:
```sh
docker compose pull
```
Photoprism is running on: https://photos.allisonandmoni.online/
I have set up a Systemd service and timer to automatically run the import once an hour. They can be found:
* [photoprism_import.service](./scripts/photoprism_import.service)
* [photoprism_import_timer.service](./scripts/photoprism_import_timer.service)
To install:
```sh
cp -v photoprism_import.service /etc/systemd/system/
cp -v photoprism_import.timer /etc/systemd/system/
```
Enable:
```sh
systemctl enable photoprism_import.service
systemctl enable photoprism_import.timer
```
In the `compose.yaml` file you'll notice I have the files stored in `/home/photoprism`. That's because I thought I could run it with podman as a dedicated user. I abandoned that idea and am now running it in Docker instead. The directories `/home/photoprism/Pictures` and `/home/photoprism/Import` are all owned by `root`

43
homeservers/README.md Normal file
View file

@ -0,0 +1,43 @@
# General
This file describes the setup of the servers I have running at home, with some instructions.
At the moment I'm running:
* Raspberry PI4 8GB: `ssh moni@192.168.1.108`
* Lenovo Thinkcentre M900, i5-6500T: `ssh moni@192.168.1.10`, 8GB RAM, 500G SSD
* Lenovo Thinkcentre M900, i5-6500T: `ssh moni@192.168.1.11`, 16GB RAM, 126G NVME + 1TB SSD
For Raspberry PI, see [RPI](./RPI.md). That is where the routing happens.
For Lenovo Thinkcenter, see below. That is where all the action happens.
# Lenovo Thinkcentre M900, i5-6500T
I have two Lenovo Thinkcentres, one with 8GB of ram and 500GB. The other with 16GB of ram and an NVME of 128GB and an SSD of 1GB.
The idea is to have one in production for all my servers running on `allisonandmoni.online` domain and the other is to play with.
Right now my OS of choice is AlmaLinux, but that can change with my mood.
On my production machine I am running Docker.
You don't need to be root to use it:
```sh
docker ps -a
```
Right now I'm running the following containers:
* [PhotoPrism](./PhotoPrism.md), reachable by https://photos.allisonandmoni.online
* [JellyFin](./Jellyfin.md), reachable by https://jellyfin.allisonandmoni.online/
* [Nextcloud](./Nextcloud.md), reachable by https://nextcloud.allisonandmoni.online/
* [qBittorrent](./qBittorrent.md), reachable by https://qbittorrent.allisonandmoni.online/
* [Immich](./Immich.md), reachable by https://photos2.allisonandmoni.online
# Backup and restore
I have backup and restore scripts and instructions. See here:
* [Backup](./Backup.md)
* [Restore](./Restore.md)

53
homeservers/RPI.md Normal file
View file

@ -0,0 +1,53 @@
# Raspberry PI
On the Raspberry PI I am running FreeBSD with Bastille which currently has 1 jail:
```sh
sudo bastille list
```
```
ID IP Address Hostname Path
1 192.168.1.200 caddy /usr/local/bastille/jails/caddy/root
```
The ip address 192.168.1.200 is chosen deliberately. On my router (192.168.1.1) I have the following port mappings:
* 32222 to 192.168.1.108:22 (ssh) - Maps to the Raspberry PI 8 for external access
* 80 to 192.168.1.200:80 (http) - Maps to the Caddy jail
* 443 to 192.168.1.200:443 (https) - Maps to the Caddy jail
* 3478 to 192.168.1.10 (Nextcloud talk) - This is a direct connection to the Lenovo machine.
To view the Caddy setup in the Caddy jail, run this:
```sh
sudo -i
bastille console caddy
cat /usr/local/etc/caddy/Caddyfile
```
Result:
```
www.allisonandmoni.online {
reverse_proxy 192.168.1.10:8081
}
photos.allisonandmoni.online {
reverse_proxy 192.168.1.10:2342
}
nextcloud.allisonandmoni.online {
reverse_proxy 192.168.1.10:11000
}
jellyfin.allisonandmoni.online {
reverse_proxy 192.168.1.10:8096
}
```
As you can see I have setup reverse proxies for www, photos and nextcloud for allisonandmoni.online.
The instructions for the caddy setup on my RPI4 can be found in this file:
* [Caddy on FreeBSD](../os/FreeBSD/Bastille.md#caddy)

62
homeservers/Restore.md Normal file
View file

@ -0,0 +1,62 @@
# Restore
## Borg backup
First we need to install Borg Backup:
```sh
dnf install -y borgbackup
```
## Hetzner Storage Box
So I have a Hetzner Storage Box which is reachable by:
```sh
ssh -p23 u388089@u388089.your-storagebox.de
```
There are two subdirectories:
```sh
/borgbackup # This is an actual borg backup of PhotoPrism with history and everything
/cloned_borgbackup # This is a rclone of a borg backup of nextcloud that happens on my local machine.
```
First, we're going to talk about restoring PhotoPrism
## Restore Photoprism
List:
```sh
export BORG_PASSPHRASE=''
borg list ssh://u388089@u388089.your-storagebox.de:23/./borgbackup/photoprism
```
(Optional, to see what you have) Mount a snapshot:
```sh
borg mount ssh://u388089@u388089.your-storagebox.de:23/./borgbackup/photoprism::2025-01-14_04:00 /home/moni/borg_restore/
```
Unmount it:
```sh
borg umount /home/moni/borg_restore/
```
Restore a backup
You might want to tmux first:
```sh
tmux
```
```sh
borg --progress --verbose extract ssh://u388089@u388089.your-storagebox.de:23/./borgbackup/photoprism::2025-01-14_04:00 /home/photoprism/Pictures
```
Giving a local target directory is not supported. The restore will be in a subdirectory. So if you're in `/home/moni` it will restore to `/home/moni/home/photoprism/Pictures`. You can't change this behavior.

View file

@ -0,0 +1,11 @@
# qBittorrent
Compose file:
* [compose.yaml](../containers/docker/qbittorrent/docker-compose.yml)
qBittorrent uses the same user as jellyfin which writes everything to `/home/jellyfin`
I also put the `jellyfin` uid:guid into the qbitorrent container. The files are downloaded to the `bittorrent/downloads` subdirtory of `jellyfin` home.
When I want to watch something I can copy it from the downloads directory to the media directory of jellyfin.

View file

@ -0,0 +1,8 @@
[Unit]
Description=Run Cloud Backup
[Service]
ExecStart=/bin/bash /usr/local/bin/cloud_backup.sh
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,3 @@
#!/bin/bash
/bin/bash /usr/local/bin/photoprism_backup.sh
/bin/bash /usr/local/bin/nextcloud_backup.sh

View file

@ -0,0 +1,9 @@
[Unit]
Description=Run PCloud Backup timer
[Timer]
OnCalendar=0/4:00:00
Unit=cloud_backup.service
[Install]
WantedBy=timers.target

View file

@ -0,0 +1 @@
rclone sync /root/nextcloudbackup/ hetzner:/cloned_borgbackup/nextcloud --log-file /var/log/nextcloud_backup.log --log-level INFO

View file

@ -0,0 +1,59 @@
#!/usr/bin/env bash
##
## Set environment variables
##
## if you don't use the standard SSH key,
## you have to specify the path to the key like this
export BORG_RSH='ssh -i /root/.ssh/id_ed25519'
## You can save your borg passphrase in an environment
## variable, so you don't need to type it in when using borg
export BORG_PASSPHRASE=''
##
## Set some variables
##
LOG='/var/log/photoprism_backup.log'
export BACKUP_USER='u388089'
export REPOSITORY_DIR='photoprism'
## Tip: If using with a Backup Space you have to use
## 'your-storagebox.de' instead of 'your-backup.de'
export REPOSITORY="ssh://${BACKUP_USER}@${BACKUP_USER}.your-storagebox.de:23/./borgbackup/${REPOSITORY_DIR}"
##
## Output to a logfile
##
exec > >(tee -i ${LOG})
exec 2>&1
echo "###### Backup started: $(date) ######"
##
## At this place you could perform different tasks
## that will take place before the backup, e.g.
##
## - Create a list of installed software
## - Create a database dump
##
##
## Transfer the files into the repository.
## In this example the folders root, etc,
## var/www and home will be saved.
## In addition you find a list of excludes that should not
## be in a backup and are excluded by default.
##
echo "Transfer files ..."
borg create -v --stats \
$REPOSITORY::'{now:%Y-%m-%d_%H:%M}' \
/home/photoprism/Import/ \
/home/photoprism/Pictures/
echo "###### Backup ended: $(date) ######"

View file

@ -0,0 +1,8 @@
[Unit]
Description=Run Photoprism Import
[Service]
ExecStart=docker exec photoprism-photoprism-1 photoprism import
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,9 @@
[Unit]
Description=Run Photoprism Import script hourly
[Timer]
OnCalendar=hourly
Unit=photoprism_import.service
[Install]
WantedBy=timers.target

179
laptops/Clevo_Laptop.md Normal file
View file

@ -0,0 +1,179 @@
Clevo laptop which is sold by Tuxedo computers.
# General
Set the hostname:
```sh
hostnamectl set-hostname moni-fedora # Fedora
hostnamectl set-hostname moni-opensuse # openSUSE
```
Install my favorite packages
```sh
zypper install tmux htop neovim git ncdu podman # openSUSE
dnf install tmux htop neovim git ncdu podman # Fedora
```
# Suspend when laptop lid closed
On openSUSE:
On Fedora:
```sh
nvim /usr/lib/systemd/logind.conf # Fedora & openSUSE
nvim /etc/systemd/logind.conf # Ubuntu
```
Uncomment the lines:
```conf
HandleLidSwitch=suspend
HandleLidSwitchExternalPower=suspend
HandleLidSwitchDocked=ignore
LidSwitchIgnoreInhibited=yes
```
You need to reboot before it takes effect.
# Wake on suspend
There is a bug in Linux kernel 6. This article explains this:
https://bugzilla.redhat.com/show_bug.cgi?id=2162013
Somehow the touchpad keeps waking up the laptop.
```sh
cat /proc/acpi/wakeup
```
Should return:
```
Device S-state Status Sysfs node
GPP0 S0 *disabled
GPP1 S0 *disabled
GP17 S0 *enabled pci:0000:00:08.1
```
## Temporarily disable
To temporarily disable it do this:
```sh
echo disabled > /sys/bus/i2c/devices/i2c-FTCS1000:00/power/wakeup
```
## Persistent settings
As root:
```sh
nvim /etc/systemd/system/disable-wakeup.service
```
Contents:
```
[Unit]
Description=Disable wakeup triggers
[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo disabled > /sys/bus/i2c/devices/i2c-FTCS1000\:00/power/wakeup ; echo GP17 > /proc/acpi/wakeup"
ExecStop=/bin/sh -c "echo disabled > /sys/bus/i2c/devices/i2c-FTCS1000\:00/power/wakeup ; echo GP17 > /proc/acpi/wakeup"
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
Then simply enable and start it:
```sh
systemctl enable disable-wakeup.service
systemctl start disable-wakeup.service
```
Reboot the laptop and check to see if the systemd unit works:
```sh
systemctl status disable-wakeup.service
```
```sh
cat /proc/acpi/wakeup
cat /sys/bus/i2c/devices/i2c-FTCS1000\:00/power/wakeup
```
Test it by suspending the laptop. You can also use:
```sh
systemctl suspend -i
```
# Tuxedo control center
Instructions: https://www.tuxedocomputers.com/en/Add-TUXEDO-software-package-sources.tuxedo
## On openSUSE
See instructions on page and then:
```sh
zypper refresh && zypper install tuxedo-control-center
```
## On Fedora
```sh
nvim /etc/yum.repos.d/tuxedo.repo
```
Contents:
```
[tuxedo]
name=tuxedo
baseurl=https://rpm.tuxedocomputers.com/fedora/40/x86_64/base
enabled=1
gpgcheck=1
gpgkey=https://rpm.tuxedocomputers.com/fedora/40/0x54840598.pub.asc
skip_if_unavailable=False
```
Get the key:
```sh
wget https://rpm.tuxedocomputers.com/fedora/40/0x54840598.pub.asc
```
And install it:
```sh
rpm --import ./0x54840598.pub.asc
```
Now install the control center:
```sh
dnf update
dnf install tuxedo-control-center
```
You need to reboot before it takes effect.
# Virtualization
```sh
dnf install @virtualization
```
```sh
systemctl enable libvirtd
systemctl start libvirtd
```

88
laptops/Ideapad_510.md Normal file
View file

@ -0,0 +1,88 @@
# Lenovo ideapad 510
## Prevent suspend when lid closed
Add a new file:
```sh
nvim /etc/systemd/logind.conf.d/no-suspend-on-lid.conf
```
Add this:
```
[Login]
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
```
```sh
systemctl restart systemd-logind
```
## Wake-on-lan
See my network interfaces:
```sh
ip link show
```
```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 54:e1:ad:9d:a8:74 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DORMANT group default qlen 1000
link/ether 52:37:c4:2c:79:38 brd ff:ff:ff:ff:ff:ff permaddr 3c:f8:62:b3:7f:81
```
Enable for the ethernet
```sh
ethtool -s enp1s0 wol g
```
Make it pemanent. Create a systemd unit:
```sh
nvim /etc/systemd/system/wol.service
```
```
[Unit]
Description=Wake-on-LAN
Requires=network.target
After=network.target
[Service]
ExecStart=/usr/sbin/ethtool -s enp1s0 wol g
Type=oneshot
[Install]
WantedBy=multi-user.target
```
```sh
systemctl enable wol.service
```
Check it:
```sh
systemctl start wol.service
systemctl status wol.service
```
Suspend the laptop:
```sh
systemctl suspend
```
Wake it up again from another machine:
```sh
wakeonlan 54:e1:ad:9d:a8:74
```

2
laptops/Laptops.md Normal file
View file

@ -0,0 +1,2 @@
* [Clevo Laptop](Clevo_Laptop.md)
* [Lenovo ideapad 510](Ideapad_510.md)

90
os/AlmaLinux/AlmaLinux.md Normal file
View file

@ -0,0 +1,90 @@
# General
Remove the web console and all the other stuff around it:
```sh
dnf -y remove cockpit*
firewall-cmd --permanent --remove-service=cockpit
firewall-cmd --reload
firewall-cmd --list-all
```
Update
```sh
dnf update
```
Set hostname
```sh
hostnamectl set-hostname moni-alma
```
Set up EPEL, follow the instructions:
* https://docs.fedoraproject.org/en-US/epel/getting-started/
And then install my favorites:
```sh
dnf install -y tmux htop ncdu neovim git
```
Install docker:
```sh
dnf -y install dnf-plugins-core
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
```
Add the `moni` to the docker group:
```sh
usermod -aG docker moni
```
You need to log out and log back in and then test it:
```sh
# run without sudo
docker run -it --rm -p 8080:80 httpd:2.4
```
It will run in the foreground because we didn't pass `-d`.
Open your browser to:
* http://192.168.1.11:8080
* or http://192.168.1.10:8080 for the 8GB server
You can stop the container with CTRL+C. It should clean itself up (`--rm`).
Cleanup:
```sh
docker image prune --all --force
```
# SSH
```sh
nvim /etc/ssh/sshd_config
```
Uncomment/change these settings:
```conf
PermitRootLogin no
# PubkeyAuthentication yes <-- This is the detault, so you don't need to change this
PasswordAuthentication no
KbdInteractiveAuthentication no
```
Reload:
```sh
sudo systemctl reload sshd
```

View file

@ -0,0 +1,280 @@
# Setup
Install my favorite packages
```sh
pkg install bash sudo tmux htop neovim git bastille
```
Add "wheel" to the suoers file:
```sh
visudo
```
Change shell
```sh
chsh -s /usr/local/bin/bash
```
Do a system update:
```sh
freebsd-update fetch install
```
# Wifi
Find out what network cards we have:
```sh
pciconf -lv | grep -A1 -B3 network
```
On my Clevo laptop it looks like this:
```
re0@pci0:2:0:0: class=0x020000 rev=0x15 hdr=0x00 vendor=0x10ec device=0x8168 subvendor=0x1558 subdevice=0xa600
vendor = 'Realtek Semiconductor Co., Ltd.'
device = 'RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller'
class = network
subclass = ethernet
iwlwifi0@pci0:3:0:0: class=0x028000 rev=0x1a hdr=0x00 vendor=0x8086 device=0x2723 subvendor=0x8086 subdevice=0x0084
vendor = 'Intel Corporation'
device = 'Wi-Fi 6 AX200'
class = network
nvme0@pci0:4:0:0: class=0x010802 rev=0x00 hdr=0x00 vendor=0x144d device=0xa809 subvendor=0x144d subdevice=0xa801
```
So we have an Intel Wifi.
We're going to configure the wireless card iwlwifi0 to the interface wlan0:
```sh
ifconfig wlan0 create wlandev iwlwifi0
```
To make the change persist across reboots:
```sh
sysrc wlans_iwlwifi0="wlan0"
```
We need to set the regulatory domain:
```sh
ifconfig wlan0 regdomain ETSI country NL
```
To scan the networks. I had to run the command twice to see the list:
```sh
ifconfig wlan0 up list scan
```
I see my networks:
```
SSID/MESH ID BSSID CHAN RATE S:N INT CAPS
TMNL-3EF981_24G d8:0d:17:b9:b2:f0 11 54M -37:-96 100 EPS HTCAP WME ATH RSN WPS
TMNL-3EF981 98:0d:67:3e:f9:81 11 54M -72:-96 100 EP APCHANREP RSN WPS BSSLOAD HTCAP VHTCAP VHTOPMODE WME
TMNL-3EF981_5G d8:0d:17:b9:b2:f1 64 54M -42:-96 100 EP HTCAP VHTCAP VHTOPMODE VHTPWRENV WME ATH RSN WPS
```
I want to connect to `TMNL-3EF981_5G`. We need to edit the `/etc/wpa_supplicant.conf` file:
```sh
nvim /etc/wpa_supplicant.conf
```
The contents. The password need to be set in psk.
```
country=NL
network={
ssid="TMNL-3EF981_5G"
psk="3J6YJHNRG8W7KMMF"
priority=5
}
```
To set it to use DHCP:
```sh
sysrc ifconfig_wlan0="WPA SYNCDHCP"
```
For some reason, we need to add the country code in the rc.conf:
```sh
sysrc create_args_wlan0="country NL"
```
Now bring it up!
```sh
service netif restart
```
Restart the laptop to see if it persists.
For some reason, it won't work (no suprise, wifi is awful in FreeBSD).
This worked for me after boot
```sh
ifconfig wlan0 down
ifconfig wlan0 ssid "TMNL-3EF981_5G"
ifconfig wlan0 regdomain etsi2 country NL
service netif restart
```
# X11
https://docs.freebsd.org/en/books/handbook/x11/
Don't forget to start `tmux`:
```sh
tmux
```
Add `moni` to the `video` group:
```sh
pw groupmod video -m moni
```
And then install, but don't forget to read the messages when the install is complete! Scroll up with tmux
```sh
pkg install xorg
```
This will improve mnuse and touchscreen support:
```sh
sysctl kern.evdev.rcpt_mask=6
```
And add this to `/etc/sysctl.conf` to persist it:
```sh
kern.evdev.rcpt_mask=6
```
# Amd
```sh
pkg install drm-kmod
```
```sh
sysrc kld_list+=amdgpu
```
# Kde
```sh
pkg install kde5
```
```sh
sysrc dbus_enable="YES"
```
```sh
sysctl net.local.stream.recvspace=65536
sysctl net.local.stream.sendspace=65536
```
```sh
pkg install sddm
sysrc sddm_enable="YES"
```
# Fonts
```sh
pkg install urwfonts
```
But you're not done yet, you need to add a conf file:
```sh
nvim /usr/local/etc/X11/xorg.conf.d/90-fonts.conf
```
With the following:
```
Section "Files"
FontPath "/usr/local/share/fonts/urwfonts/"
EndSection
```
# CPU
Too see your CPU 0
```sh
sysctl dev.cpu.0
```
If you don't see a temperature:
```sh
kldload amdtemp
```
Add it to startup:
```sh
sysrc kld_list+=amdtemp
```
# Linux compatibility
```sh
sysrc linux_enable="YES"
```
```sh
service linux start
```
# Final configs
My `/etc/rc.conf`
```
hostname="moni-freebsd"
ifconfig_re0="DHCP"
sshd_enable="YES"
moused_enable="YES"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"
kld_list="amdgpu amdtemp"
dbus_enable="YES"
sddm_enable="YES"
linux_enable="YES"
create_args_wlan0="country NL"
wlans_iwlwifi0="wlan0"
ifconfig_wlan0="WPA SYNCDHCP"
```
My `/etc/sysctl.conf`:
```
#
# This file is read when going to multi-user and its contents piped thru
# ``sysctl'' to adjust kernel values. ``man 5 sysctl.conf'' for details.
#
# Uncomment this to prevent users from seeing information about processes that
# are being run under another UID.
#security.bsd.see_other_uids=0
kern.evdev.rcpt_mask=6
```

View file

@ -0,0 +1,111 @@
# Setup
First time:
```sh
su -
```
Do a system update:
```sh
freebsd-update fetch install
```
Update
```sh
pkg update
```
Install my favorite packages
```sh
pkg install -y bash sudo tmux htop neovim git ncdu bastille tailscale aria2
```
Add "wheel" to the suoers file:
```sh
visudo
```
Change shell
```sh
chsh -s /usr/local/bin/bash
```
Tailscale
```sh
service tailscaled enable
service tailscaled start
tailscale up
```
# SSH
```sh
nvim /etc/ssh/sshd_config
```
Change this setting:
```
KbdInteractiveAuthentication no
```
That should be it. The config file should have these settings, including the commented lines shown as below:
```
#PermitRootLogin no
#PubkeyAuthentication yes
#PasswordAuthentication no
KbdInteractiveAuthentication no
#UsePAM yes
```
Test the setting
```sh
sshd -t
```
Reload:
```sh
service sshd reload
```
# PF
Note, if you're using Bastille, the `/etc/pf.conf` file is going to look different. See [Bastille](../../containers/Bastille/Bastille.md).
Now we need to get the filewall going.
```sh
nvim /etc/pf.conf
```
Contents:
```
ext_if="em0"
block in all
pass in on $ext_if proto tcp to ($ext_if) port ssh
pass in on $ext_if proto tcp to ($ext_if) port 80
pass in on $ext_if proto tcp to ($ext_if) port 443
pass out all keep state
```
```sh
sysrc pf_enable=yes
service pf start
```
If you get the error 'no host key files found` then
```sh
ssh-keygen -A
```

View file

@ -0,0 +1,94 @@
# General
Default username passwords are:
```
freebsd
freebsd
```
and
```
root
root
```
```sh
ssh freebsd@192.168.1.108
```
Setup ntpd
You need to make sure that your date is close to the real time
```sh
date 202406211441
```
Set the timezone
```sh
tzsetup
```
```sh
sysrc ntpd_enable=YES
```
Set the time:
```sh
ntpdate -v -b in.pool.ntp.org
```
Start the service
```sh
service ntpd start
```
Update the system
```sh
pkg update
```
Install my favorite packages
```sh
pkg install bash sudo tmux htop neovim git bastille
```
Add "wheel" to the suoers file:
```sh
visudo
```
Change shell
```sh
chsh -s /usr/local/bin/bash
```
Add a user
```sh
adduser
```
Change the hostname
```sh
sysrc hostname="rp4-8"
```
Delete the freebsd user that comes with the standard installation:
```sh
rmuser freebsd
```
* [SSH instructions](FreeBSD_on_Lenovo_Thinkcentre.md#ssh)
* [PF instructions](FreeBSD_on_Lenovo_Thinkcentre.md#pf). Be careful, the network interface on the PI is called `genet0` not `em0`.

53
os/FreeBSD/Storage.md Normal file
View file

@ -0,0 +1,53 @@
# Storage
First we need to know what drives we have:
```sh
geom disk list
```
Show the partitions:
```sh
gpart show
```
In FreeBSD the partitions are named with suffix `pX`, for example `p1`, `p2`, etc.
To mount the first partition of the external harddrive:
```sh
# directory needs to exist
mkdir /mnt/usb
# mount the first partition p1
mount -t /dev/da0p1 /mnt/usb
```
# ZFS
The handbook is actually quite comprehensive:
* https://docs.freebsd.org/en/books/handbook/zfs/
In order for ZFS to work, we need to enable it. On the Raspberry PI it is not enabled by default.
```sh
service zfs enable
service zfs start
```
You need empty space, either an empty partition or drive.
# Mounting different filesystems (for example, a USB SDD)
For ext4, see: https://docs.freebsd.org/en/books/handbook/filesystems/index.html#filesystems-linux
For NTFS, see: https://docs.freebsd.org/en/books/handbook/disks/#using-ntfs
Take into account that NTFS uses "Slices", not "Partitions" so mounting the external NTFS harddrive on the Raspberry PI looks like this:
```sh
ntfs-3g /dev/da0s1 /mnt/usb
```

4
ssh.md Normal file
View file

@ -0,0 +1,4 @@
```sh
eval `ssh-agent -s` && ssh-add -k
ssh -t -A moni@143.179.250.91 -p 32222 ssh moni@192.168.1.10
```