Python
meine selbstgebaute Cloud
Die Vorteile einer Cloud-Datensicherung sind wohl unbestritten. Mein Vertrauen in Cloud-Anbieter (speziell die aus "Übersee") ist allerdings begrenzt. Außerdem sind sie nicht so preiswert, wie meine selbst programmierte Lösung.
Für 120 GB Webspace mit FTP-Zugang zahle ich monatlich nur 0,97 Euro. Dort findet sich also auch ausreichend Platz für meine "private Cloud".
Meine sicherungswürdigen Dateien, die alle in einem Verzeichnis meines PCs liegen, sichere ich in meinem Webspace. So habe ich von jedem meiner Geräte mit Internetzugang (und einem PYTHON-Interpreter!) Zugriff auf meine aktuellen Dateien.
Ich habe mich für die Programmiersprache PYTHON entschieden, weil man unter allen (?) Betriebssystemen einen kostenlosen PYTHON-Interpreter findet.
Mit drei PYTHON-Skripten habe ich mir eine (bei Bedarf vollautomatische) Cloud-Datensicherung programmiert.
Ich ver- und entschlüssele (ausschließlich lokal !) mithilfe der "Fernet"-Bibliothek.
Bei Bedarf (oder zeitgesteuert) wird auf meinem PC das Upload-Skript gestartet. zuerst prüft dieses, ob seit der letzten Sicherung Dateien neu erstellt bzw. geändert wurden. Ggf. werden nur von diesen AES-verschlüsselte Kopien erzeugt, die dann wiederum verschlüsselt per FTP zu meinem Webspace übertragen werden.
Falls ich irgendwann eine im Webspace gesicherte Datei benötigen sollte, starte ich das Download-Skript und wähle die benötigte Datei aus. Das Entschlüsseln dieser Datei kann ich anschließend wiederum lokal durchführen.
hier mein Download-Skript:
Falls das Skript (s.u.) so nicht funktioniert, erkundigt Euch beim Webspace-Anbieter nach dem Anmelde-Verfahren des FTP-Servers.
#============================================================
import pathlib, os
import ftplib
from ftplib import FTP_TLS
import time
from datetime import datetime, timezone
from datetime import timedelta
def s2z(ds): # originalen Zeitstring aus DIR zu Zeit konvertieren
if ds[9] == ":": # Datumsangabe mit Zeit ohne Jahr = aktuelles Jahr
ds = datetime.now().strftime("%Y") + " " + ds
z = datetime.strptime(ds,"%Y %b %d %H:%M")
else: # Datum ohne Zeit mit Jahr
z = datetime.strptime(ds,"%b %d %Y")
return z
##############################################
if __name__ == '__main__':
ftps_server = "meinFTPserver.de" # ändern!
ftps_user = "meinBenutzername" # ändern!
ftps_pw = "meinFTPpasswort" # ändern!
quell_verz = "//htdocs//wichtig//aes//" # ändern!
ziel_verz = "C:/wichtig/aes/" # ändern!
ftps = FTP_TLS(ftps_server)
ftps.login(ftps_user, ftps_pw)
ftps.prot_p() # Übertragung komplett verschlüsselt
ftps.encoding = "utf-8"
ftps.cwd(quell_verz)
data1=[]
data2=[] # nur für Dateien
ftps.dir(data1.append) # DIR in Liste einlesen
print("=" * 50)
print(quell_verz)
print("=" * 50)
i=0
for x in data1:
if x[0] == "-": # nur wenn kein Verzeichnis
data2.append(x)
i = i + 1
dateiname = x[56:] # Dateiname
date_time = s2z(x[43:55]) # Datum-Zeit aus originalem Datum-Zeit-String
dzs = date_time.strftime(" %d.%m.%Y %H:%M ") # zu neuem Datum-Zeit-String
print(str(i).rjust(2), x[32:42], dzs, dateiname)
# Zähler Größe Dat-Zeit Name
print()
k = int(input("für Download Nr. eingeben (0=Ende): "))
if k < 1 or k > data2.__len__():
print("Abbruch")
else:
os.chdir(ziel_verz) # lokales Zielverz. setzen (sonst aktuelles Verz.)
downd = (data2[k-1][56:].strip()) # ausgewählter Dateiname
diff=0
server_z = (date_time - datetime(1970, 1, 1)).total_seconds()
print("Zeit remote: ", server_z)
lokale_d = downd[:-4] # lokal schon vorhanden ?
print(lokale_d)
try:
lokale_z = os.path.getmtime(downd) # wann zuletzt geändert ?
print("Zeit lokal ",lokale_z)
diff = server_z - lokale_z # wenn diff > 0, dann ist Serverdatei aktueller
print("Diff: ",diff)
except:
print(f"{downd} lokal noch nicht vorhanden")
diff = 99
if diff > 0: # ok , Download
with open(downd, "wb") as file:
ftps.retrbinary(f"RETR " + downd, file.write) # Download im binary mode
print(f"{downd} Download fertig, lokal entschlüsseln mit _aes_ent.py")
else:
print(f"{downd} - kein Download - lokale Datei ist aktueller")
ftps.quit
#===========================================================================
