Add memos
This commit is contained in:
37
memos/backup.sh
Executable file
37
memos/backup.sh
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Note: use rclone for backup, needs manually configuration.
|
||||||
|
|
||||||
|
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus"
|
||||||
|
|
||||||
|
DATA=""
|
||||||
|
DB=""
|
||||||
|
LOCAL_BACKUP="$HOME/.local/backup"
|
||||||
|
REMOTE=""
|
||||||
|
DB_USERNAME=""
|
||||||
|
DB_PASSWORD=""
|
||||||
|
DB_DATABASE=""
|
||||||
|
CONTAINER_DB=""
|
||||||
|
SERVICE=""
|
||||||
|
|
||||||
|
STAGING_DIR=$(mktemp -d)
|
||||||
|
mkdir -p $LOCAL_BACKUP
|
||||||
|
DATE=$(date +%F-%H-%M-%S)
|
||||||
|
BACKUP_NAME="backup_$DATE.tar.gz"
|
||||||
|
|
||||||
|
systemctl --user stop $SERVICE
|
||||||
|
podman exec $CONTAINER_DB pg_dump -U $DB_USERNAME -F c -d $DB_DATABASE > $STAGING_DIR/db.dump
|
||||||
|
|
||||||
|
cp -r "$DATA" "$STAGING_DIR/data"
|
||||||
|
cp -r "$DB" "$STAGING_DIR/db"
|
||||||
|
tar -czf "$LOCAL_BACKUP/$BACKUP_NAME" -C "$STAGING_DIR" .
|
||||||
|
|
||||||
|
ls -1t "$LOCAL_BACKUP"/backup_*.tar.gz | tail -n +6 | xargs -r rm --
|
||||||
|
|
||||||
|
|
||||||
|
/usr/bin/rclone sync $LOCAL_BACKUP $REMOTE > /dev/null
|
||||||
|
|
||||||
|
rm -rf $STAGING_DIR
|
||||||
|
|
||||||
|
systemctl --user start $SERVICE
|
||||||
144
memos/deploy.sh
Executable file
144
memos/deploy.sh
Executable file
@@ -0,0 +1,144 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./env.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
services=("$CONTAINER_PREFIX-$CONTAINER_SERVICE.service"
|
||||||
|
"$CONTAINER_PREFIX-$CONTAINER_DB.service"
|
||||||
|
)
|
||||||
|
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
if systemctl --user list-units --full --all | grep -q "$service"; then
|
||||||
|
echo "Stopping $service..."
|
||||||
|
systemctl --user stop $service
|
||||||
|
echo "$service stopped."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
containers=(
|
||||||
|
"$CONTAINER_SERVICE"
|
||||||
|
"$CONTAINER_DB"
|
||||||
|
)
|
||||||
|
|
||||||
|
for container in "${containers[@]}"; do
|
||||||
|
if podman container exists "$container"; then
|
||||||
|
echo "Stop and delete existing container $container"
|
||||||
|
if podman inspect -f '{{.State.Running}}' "$container" | grep -q true; then
|
||||||
|
podman stop "$container"
|
||||||
|
fi
|
||||||
|
podman rm "$container"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! podman network exists $NETWORK; then
|
||||||
|
podman network create $NETWORK
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $DATA_FOLDER
|
||||||
|
mkdir -p $DB_FOLDER
|
||||||
|
mkdir -p $USER_SYSTEMD
|
||||||
|
|
||||||
|
podman create \
|
||||||
|
--name $CONTAINER_DB \
|
||||||
|
--network $NETWORK \
|
||||||
|
--userns=keep-id \
|
||||||
|
--restart=always \
|
||||||
|
-p $PORT_DB:5432 \
|
||||||
|
-e POSTGRES_USER=$DB_USER \
|
||||||
|
-e POSTGRES_PASSWORD=$DB_PASSWORD \
|
||||||
|
-e POSTGRES_DB=$DB_NAME \
|
||||||
|
-e POSTGRES_HOST_AUTH_METHOD=trust \
|
||||||
|
-v "$DB_FOLDER:/var/lib/postgresql/data:Z" \
|
||||||
|
docker.io/library/postgres:16
|
||||||
|
|
||||||
|
podman generate systemd \
|
||||||
|
--new \
|
||||||
|
--name $CONTAINER_DB \
|
||||||
|
--files --restart-policy always --container-prefix=$CONTAINER_PREFIX > /dev/null
|
||||||
|
|
||||||
|
mv $CONTAINER_PREFIX-$CONTAINER_DB.service $USER_SYSTEMD
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable --now $CONTAINER_PREFIX-$CONTAINER_DB.service
|
||||||
|
echo "Wait for PostgreSQL..."
|
||||||
|
until podman exec $CONTAINER_DB pg_isready -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "PostgreSQL ready"
|
||||||
|
|
||||||
|
podman create \
|
||||||
|
--name $CONTAINER_SERVICE \
|
||||||
|
--network $NETWORK \
|
||||||
|
--restart=always \
|
||||||
|
-p $PORT_WEB:5230 \
|
||||||
|
-v "$DATA_FOLDER:/var/opt/memos:Z" \
|
||||||
|
-e MEMOS_DRIVER=postgres \
|
||||||
|
-e MEMOS_DSN="postgresql://$DB_USER:$DB_USER@$HOST_DB:$PORT_DB/memos?sslmode=disable" \
|
||||||
|
docker.io/neosmemo/memos:stable
|
||||||
|
|
||||||
|
podman generate systemd \
|
||||||
|
--new \
|
||||||
|
--name $CONTAINER_SERVICE \
|
||||||
|
--files \
|
||||||
|
--container-prefix=$CONTAINER_PREFIX \
|
||||||
|
--restart-policy=always
|
||||||
|
|
||||||
|
sed -i "/^\[Unit\]/a After=$CONTAINER_PREFIX-$CONTAINER_DB.service \nRequires=$CONTAINER_PREFIX-$CONTAINER_DB.service" $CONTAINER_PREFIX-$CONTAINER_SERVICE.service
|
||||||
|
|
||||||
|
mv $CONTAINER_PREFIX-$CONTAINER_SERVICE.service $USER_SYSTEMD
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable --now $CONTAINER_PREFIX-$CONTAINER_SERVICE.service
|
||||||
|
|
||||||
|
sudo loginctl enable-linger $USER
|
||||||
|
|
||||||
|
# generate haproxy blocks
|
||||||
|
sudo mkdir -p $SERVICE_DIR
|
||||||
|
echo "crt $SSL_PATH/fullchain.pem" | sudo tee $SERVICE_DIR/cert.block > /dev/null
|
||||||
|
ACL_CFG=$(cat <<EOF
|
||||||
|
acl is_memos hdr(host) -i $DOMAIN
|
||||||
|
use_backend memos_backend if is_memos
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
echo "$ACL_CFG" | sudo tee $SERVICE_DIR/acl.block > /dev/null
|
||||||
|
BACKEND_CFG=$(cat <<EOF
|
||||||
|
backend memos_backend
|
||||||
|
mode http
|
||||||
|
option httpchk GET /
|
||||||
|
option forwardfor
|
||||||
|
option http-server-close
|
||||||
|
|
||||||
|
server memoshttp 127.0.0.1:$PORT_WEB alpn http/1.1 check
|
||||||
|
# === CORS & proxy headers ===
|
||||||
|
http-request set-header X-Forwarded-For %[src]
|
||||||
|
http-request set-header X-Forwarded-Proto https
|
||||||
|
http-request set-header X-Forwarded-Host %[req.hdr(Host)]
|
||||||
|
http-request set-header X-Real-IP %[src]
|
||||||
|
|
||||||
|
# === WebSocket support ===
|
||||||
|
http-request set-header Connection "upgrade" if { req.hdr(Upgrade) -i websocket }
|
||||||
|
http-request set-header Upgrade "%[req.hdr(Upgrade)]" if { req.hdr(Upgrade) -i websocket }
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
echo "$BACKEND_CFG" | sudo tee $SERVICE_DIR/backend.block > /dev/null
|
||||||
|
|
||||||
|
echo "Generate backup script"
|
||||||
|
BACKUP_FILE="memos_backup.sh"
|
||||||
|
cp backup.sh $BACKUP_FILE
|
||||||
|
sed -i "s|^DATA=\"\"|DATA=\"$DATA_FOLDER\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^DB=\"\"|DB=\"$DB_FOLDER\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^DB_USERNAME=\"\"|DB_USERNAME=\"$DB_USER\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^DB_DATABASE=\"\"|DB_DATABASE=\"$DB_NAME\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^DB_PASSWORD=\"\"|DB_PASSWORD=\"$DB_PASSWORD\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^LOCAL_BACKUP=\"\$HOME/.local/backup\"|LOCAL_BACKUP=\"\$HOME/.local/backup/$CONTAINER_PREFIX\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^CONTAINER_DB=\"\"|CONTAINER_DB=\"$CONTAINER_DB\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^REMOTE=\"\"|REMOTE=\"$BACKUP_REMOTE\"|" "$BACKUP_FILE"
|
||||||
|
sed -i "s|^SERVICE=\"\"|SERVICE=\"${CONTAINER_PREFIX}-${CONTAINER_SERVICE}.service\"|" "$BACKUP_FILE"
|
||||||
|
|
||||||
|
mv $BACKUP_FILE $APP_DIR
|
||||||
|
echo "Backup script generated at $APP_FOLDER/$BACKUP_FILE"
|
||||||
|
echo "Backup script will be run every day at 2:00 AM"
|
||||||
|
crontab -l | grep -v "$APP_FOLDER/$BACKUP_FILE" | crontab -
|
||||||
|
(crontab -l 2>/dev/null; echo "0 2 * * * $APP_DIR/$BACKUP_FILE") | crontab -
|
||||||
|
echo "Backup script added to crontab"
|
||||||
|
|
||||||
|
echo "Deploy completed, manually run haproxy to generate new config."
|
||||||
21
memos/env.sh
Normal file
21
memos/env.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
CONTAINER_PREFIX="memos"
|
||||||
|
CONTAINER_SERVICE="memos"
|
||||||
|
CONTAINER_DB="memos-db"
|
||||||
|
NETWORK="memos-net"
|
||||||
|
APP_DIR="$HOME/.local/share/memos"
|
||||||
|
DATA_FOLDER=$APP_DIR/data
|
||||||
|
DB_FOLDER=$APP_DIR/db
|
||||||
|
USER_SYSTEMD="$HOME/.config/systemd/user"
|
||||||
|
HOST_DB="host.containers.internal"
|
||||||
|
PORT_DB=5632
|
||||||
|
PORT_WEB=5630
|
||||||
|
DB_USER="memos"
|
||||||
|
DB_PASSWORD="memos"
|
||||||
|
DB_NAME="memos"
|
||||||
|
|
||||||
|
DOMAIN=""
|
||||||
|
SSL_PATH=$HOME/.config/ssl/$DOMAIN
|
||||||
|
HAPROXY_CFG_DIR="/etc/haproxy"
|
||||||
|
HAPROXY_CFG="$HAPROXY_CFG_DIR/haproxy.cfg"
|
||||||
|
SERVICE_DIR="$HAPROXY_CFG_DIR/services/$DOMAIN"
|
||||||
|
BACKUP_REMOTE="onedrive-tianyu:Backups/memos"
|
||||||
43
memos/uninstall.sh
Executable file
43
memos/uninstall.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./env.sh
|
||||||
|
|
||||||
|
services=("$CONTAINER_PREFIX-$CONTAINER_SERVICE.service"
|
||||||
|
"$CONTAINER_PREFIX-$CONTAINER_DB.service"
|
||||||
|
)
|
||||||
|
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
if systemctl --user list-units --full --all | grep -q "$service"; then
|
||||||
|
echo "Stopping $service..."
|
||||||
|
systemctl --user stop $service
|
||||||
|
echo "$service stopped."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
containers=(
|
||||||
|
"$CONTAINER_SERVICE"
|
||||||
|
"$CONTAINER_DB"
|
||||||
|
)
|
||||||
|
|
||||||
|
for container in "${containers[@]}"; do
|
||||||
|
if podman container exists "$container"; then
|
||||||
|
echo "Stop and delete existing container $container"
|
||||||
|
if podman inspect -f '{{.State.Running}}' "$container" | grep -q true; then
|
||||||
|
podman stop "$container"
|
||||||
|
fi
|
||||||
|
podman rm "$container"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
systemctl --user disable --now $service
|
||||||
|
rm $USER_SYSTEMD/$service
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo rm -r $SERVICE_DIR
|
||||||
|
crontab -l | grep -v "$APP_DIR/$BACKUP_FILE" | crontab -
|
||||||
|
|
||||||
|
echo "Uninstall complete. Manually run haproxy config to rebuild config. Manually remove data directory
|
||||||
|
- $APP_DIR
|
||||||
|
- $HOME/.local/backup/$CONTAINER_PREFIX
|
||||||
|
if needed."
|
||||||
Reference in New Issue
Block a user