From f349c94465987082d0d36463540db0d79b91f8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Fernandes?= Date: Sun, 11 Jun 2023 09:33:09 +0100 Subject: [PATCH] feat: currently in production --- .gitignore | 6 +- README.md | 86 +++++++---- docker/Dockerfile | 3 +- docker/docker-compose.yaml | 143 +++++++++--------- .../nextcloud-homessistant-dashboard.png | Bin 8617 -> 0 bytes docs/setup.md | 46 ------ 6 files changed, 139 insertions(+), 145 deletions(-) delete mode 100644 docs/images/nextcloud-homessistant-dashboard.png delete mode 100644 docs/setup.md diff --git a/.gitignore b/.gitignore index dfdb08d..8b476b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -**.env.** -.env -localSettings +**.env.** +.env +localSettings diff --git a/README.md b/README.md index d83a2ad..be903b2 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,60 @@ -# cloud.limbosolutions.com - -Welcome to public repository of [https://cloud.limbosolutions.com](https://cloud.limbosolutions.com) - -Using [NextCloud](https://nextcloud.com/) - -## Setup - -- Docker -_Currently hosted on an ubuntu lxc container with docker and portainer [+ information](https://git.limbosolutions.com/kb/lxc)._ - -- [NextCloud Custom Docker Image](docker/Dockerfile) with smbclient extensions -- [Duplicati Image with mySql client](https://git.limbosolutions.com/kb/duplicati/src/branch/main/docker/mysqlclient/README.md) - -[Docker Compose File](docker-compose.yaml) - -[Check](doc/setup.md) for setup information. - -## NextCloud CLI - -``` bash - -#force file scan for specfic user -docker exec --user www-data nextcloud php occ files:scan USERNAME - -``` +# cloud.limbosolutions.com + +Welcome to public repository of [https://cloud.limbosolutions.com](https://cloud.limbosolutions.com) + +Using [NextCloud](https://nextcloud.com/) + + + +## Requirements + +- Docker +- Docker Compose +- Portainer (optional) +- [NextCloud Custom Docker Image](docker/Dockerfile) with smbclient extensions +- [Duplicati Image with mySql client](https://git.limbosolutions.com/kb/duplicati/src/branch/main/docker/mysqlclient/README.md) + + + +## NextCloud CLI + +``` bash + +#force file scan for specfic user +docker exec --user www-data nextcloud php occ files:scan USERNAME + +``` + + +## Setup + +[Docker Compose File](docker/ocker-compose.yaml) + +## Backup and Restore + +Using [custom duplicati image](https://git.limbosolutions.com/kb/duplicati) to daily backups files and databases. Every action (backup/restore) creates an measurement in influxdb for reporting and alerts. + + +### Duplicati - Default Options + +Notify Influxdb. + +--run-script-after=duplicati-influxdb-notify + +### Duplicati - wiki job Options + +Create db dump. + +run-script-before-required:duplicati-mysql-backup + +### Restore Database + +```bash +#select a file to import +ls /db-dumps +#select a file to import +DB_FILE= "file name to import" +mysql --host db -uroot -p ${MYSQL_DATABASE} < /db-dumps/$DB_FILE +#root password (root password is the enviromnent variable ${MYSQL_ROOT_PASSWORD}) +``` + diff --git a/docker/Dockerfile b/docker/Dockerfile index af2d949..c75f424 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,2 +1,3 @@ -FROM nextcloud:25.0 +#image name : nextcloud-smbclient:25.0 +FROM nextcloud:25.0 RUN apt update;apt install -y smbclient libsmbclient-dev;pecl install smbclient;echo "extension=smbclient.so" >> /usr/local/etc/php/conf.d/nextcloud.ini \ No newline at end of file diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index fd4cbf2..34a3e4a 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -1,69 +1,74 @@ -version: '2' -services: - db: - image: mariadb:10.5 - restart: always - command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW - volumes: - - db:/var/lib/mysql - environment: - - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - - MYSQL_PASSWORD=${MYSQL_PASSWORD} - - MYSQL_DATABASE=${MYSQL_DATABASE} - - MYSQL_USER=${MYSQL_USER} - app: - image: nextcloud-smbclient:latest - restart: always - ports: - - ${APP_PORT}:80 - links: - - db - volumes: - - html:/var/www/html - environment: - - MYSQL_PASSWORD=${MYSQL_PASSWORD} - - MYSQL_DATABASE=${MYSQL_DATABASE} - - MYSQL_USER=${MYSQL_USER} - - MYSQL_HOST=${MYSQL_HOST} - - PHP_MEMORY_LIMIT=2048M - duplicati: - image: duplicati-mysqlclient:latest - environment: - - DB_HOST=${MYSQL_HOST} - - DB_NAME=${MYSQL_DATABASE} - - DB_USER=${MYSQL_USER} - - DB_PASSWORD=${MYSQL_PASSWORD} - - DB_BACKUP_TARGETFOLDER=${DB_BACKUP_TARGETFOLDER} - volumes: - - duplicati_data:/data - - db:/backup/db_data:ro - - html:/backup/app_data:ro - - duplicati_data:/backup/duplicati_data:ro - - db-dumps:${DB_BACKUP_TARGETFOLDER} - ports: - - ${DUPLICATI_PORT}:8200 - restart: unless-stopped - code-server: - image: lscr.io/linuxserver/code-server:latest - environment: - #- PUID=1000 - #- PGID=1000 - - TZ=Europe/London - - PASSWORD=${ADMIN_PASSWORD} #optional - #- HASHED_PASSWORD= #optional - - SUDO_PASSWORD=${ADMIN_PASSWORD} #optional - #- SUDO_PASSWORD_HASH= #optional - #- PROXY_DOMAIN=code-server.my.domain #optional - - DEFAULT_WORKSPACE=/config/workspace #optional - volumes: - - code-server_config:/config - - html:/data/nextcloud_html - ports: - - 8445:8443 - restart: unless-stopped -volumes: - html: - db: - duplicati_data: - db-dumps: - code-server_config: +version: '2' +services: + db: + image: mariadb:10.5 + restart: always + command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW + volumes: + - db:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + app: + image: nextcloud-smbclient:25.0 + restart: always + ports: + - ${APP_PORT}:80 + links: + - db + volumes: + - html:/var/www/html + environment: + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_HOST=${MYSQL_HOST} + - PHP_MEMORY_LIMIT=2048M + duplicati: + image: duplicati-mysqlclient:latest + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - INFLUXDB_SERVER=${INFLUXDB_SERVER} + - INFLUXDB_BUCKET=${INFLUXDB_BUCKET} + - INFLUXDB_ORG=${INFLUXDB_ORG} + - INFLUXDB_TOKEN=${INFLUXDB_TOKEN} + - INFLUXDB_CLIENT_HOSTNAME=${INFLUXDB_CLIENT_HOSTNAME} + - DB_BACKUP_TARGETFOLDER=/bck/db_dumps + volumes: + - duplicati_data:/data + - db:/bck/db_data:ro + - html:/bck/app_data:ro + - duplicati_data:/bck/duplicati_data:ro + - db-dumps:/bck/db_dumps + ports: + - ${DUPLICATI_PORT}:8200 + restart: unless-stopped + code-server: + image: lscr.io/linuxserver/code-server:latest + environment: + #- PUID=1000 + #- PGID=1000 + - TZ=Europe/London + - PASSWORD=${ADMIN_PASSWORD} #optional + #- HASHED_PASSWORD= #optional + - SUDO_PASSWORD=${ADMIN_PASSWORD} #optional + #- SUDO_PASSWORD_HASH= #optional + #- PROXY_DOMAIN=code-server.my.domain #optional + - DEFAULT_WORKSPACE=/config/workspace #optional + volumes: + - code-server_config:/config + - html:/data/nextcloud_html + ports: + - 8445:8443 + restart: unless-stopped +volumes: + html: + db: + duplicati_data: + db-dumps: + code-server_config: diff --git a/docs/images/nextcloud-homessistant-dashboard.png b/docs/images/nextcloud-homessistant-dashboard.png deleted file mode 100644 index b0005f61448950fb82a2679c00e8edf3c1060131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8617 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 Z&!Z#1hv9x