diff --git a/config/server/nexus.conf b/config/server/nexus.conf
index 8eab2815fb445638f7e39edf98c86075357a022f..7e1cd386f74710504544b70c8eb6f3ef473a4e71 100644
--- a/config/server/nexus.conf
+++ b/config/server/nexus.conf
@@ -27,7 +27,7 @@ locked_time_hours = 4.0
 
 [limits]
 
-max_upload_size = 16M
+max_upload_size = 128M
 
 # We estimate that KVM allows for this amount of RAM saving in % (due to page sharing across VMs).
 # 30% seems to be a pretty conservative estimate.
diff --git a/src/client/cmdVM/vmImportDir.go b/src/client/cmdVM/vmImportDir.go
index 03cb894e34c99d51348a94d0020a24d2ec542275..f1a22388099342174073b97b501630a02975ff33 100644
--- a/src/client/cmdVM/vmImportDir.go
+++ b/src/client/cmdVM/vmImportDir.go
@@ -2,6 +2,7 @@ package cmdVM
 
 import (
 	u "nexus-client/utils"
+	"nexus-common/utils"
 	libclient "nexus-libclient/vm"
 
 	"os"
@@ -59,7 +60,7 @@ func (cmd *ImportDir) Run(args []string) int {
 
 	statusCode := 0
 
-	tmpTarGzFile, err := u.GetRandomTempFilename()
+	tmpTarGzFile, err := utils.GetRandomTempFilename()
 	if err != nil {
 		u.PrintlnErr(err)
 		return 1
diff --git a/src/client/utils/files.go b/src/client/utils/files.go
index 0f0f7fd6488c2bacc319f0143262084455e157d0..c8dcf2d4c0164d984efb4a7873485b0eb61fa4be 100644
--- a/src/client/utils/files.go
+++ b/src/client/utils/files.go
@@ -10,8 +10,6 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
-
-	"github.com/google/uuid"
 )
 
 // Creates a tar.gz archive of dir and all its files and subdirectories.
@@ -72,13 +70,3 @@ func TarGzDir(dir, archive string) error {
 
 	return nil
 }
-
-func GetRandomTempFilename() (string, error) {
-	tempDir := os.TempDir()
-	uuid, err := uuid.NewRandom()
-	if err != nil {
-		return "", errors.New("Failed creating random UUID: " + err.Error())
-	}
-	randName := "temp_" + uuid.String()
-	return filepath.Join(tempDir, randName), nil
-}
diff --git a/src/common/utils/files.go b/src/common/utils/files.go
index 729503afc05dc11609c0eb56374d0095a4e16865..600f5fb4a8901b27bffd29dc2ab5c3f952e05603 100644
--- a/src/common/utils/files.go
+++ b/src/common/utils/files.go
@@ -3,6 +3,9 @@ package utils
 import (
 	"errors"
 	"os"
+	"path/filepath"
+
+	"github.com/google/uuid"
 )
 
 // Returns true if the specified file exists, false otherwise.
@@ -10,3 +13,28 @@ func FileExists(filename string) bool {
 	_, err := os.Stat(filename)
 	return !errors.Is(err, os.ErrNotExist)
 }
+
+func GetRandomTempFilename() (string, error) {
+	tempDir := os.TempDir()
+	uuid, err := uuid.NewRandom()
+	if err != nil {
+		return "", errors.New("Failed creating random UUID: " + err.Error())
+	}
+	randName := "temp_" + uuid.String()
+	return filepath.Join(tempDir, randName), nil
+}
+
+func CreateRandomEmptyFile() (string, error) {
+	filePath, err := GetRandomTempFilename()
+	if err != nil {
+		return "", err
+	}
+
+	file, err := os.Create(filePath)
+	if err != nil {
+		return "", err
+	}
+	file.Close()
+
+	return filePath, nil
+}
diff --git a/src/server/exec/Guestfish.go b/src/server/exec/Guestfish.go
index e30750c9ed5110d275b953ccc052db1bec89824c..f3c649c6847e7c506352f1e0a4f9403f89336286 100644
--- a/src/server/exec/Guestfish.go
+++ b/src/server/exec/Guestfish.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"os/exec"
+	"path/filepath"
 	"strings"
 )
 
@@ -22,27 +23,55 @@ func CheckGuestfish() error {
 	return nil
 }
 
-// Copies and unarchives a local tar.gz archive into a directory (vmDir) inside the VM's filesystem.
-func CopyToVM(vmDiskFile, tarGzFile, vmDir string) error {
-	cmd := exec.Command(conf.Tools.Guestfish, "--rw", "-i", "tar-in", "-a", vmDiskFile, tarGzFile, vmDir, "compress:gzip")
+// Uploads and unarchives a local tar.gz archive into a directory (vmDir) inside the VM's filesystem.
+func DearchiveToVM(vmDiskFile, localTarGzFile, vmDir string) error {
+	cmd := exec.Command(conf.Tools.Guestfish, "--rw", "-i", "tar-in", "-a", vmDiskFile, localTarGzFile, vmDir, "compress:gzip")
 	stdoutStderr, err := cmd.CombinedOutput()
 	if err != nil {
 		output := fmt.Sprintf("[%s]", stdoutStderr)
-		msg := "Failed writing to \"" + vmDir + "\" in qcow (" + vmDiskFile + ")"
+		msg := "Failed dearchiving to \"" + vmDir + "\" in VM"
 		log.Error(msg + ": " + output)
 		return errors.New(msg)
 	}
 	return nil
 }
 
-// Recursively copies a directory in the VM's filesystem (vmDir) into a tar.gz archive.
-func CopyFromVM(vmDiskFile, vmDir, tarGzFile string) error {
-	cmd := exec.Command(conf.Tools.Guestfish, "--ro", "-i", "tar-out", "-a", vmDiskFile, vmDir, tarGzFile, "compress:gzip")
+// Uploads a local file into a directory (vmDir) inside the VM's filesystem.
+func CopyToVM(vmDiskFile, localFile, vmDir string) error {
+	filename := filepath.Base(localFile)
+	cmd := exec.Command(conf.Tools.Guestfish, "--rw", "-i", "upload", "-a", vmDiskFile, localFile, filepath.Join(vmDir, filename))
 	stdoutStderr, err := cmd.CombinedOutput()
 	if err != nil {
 		output := fmt.Sprintf("[%s]", stdoutStderr)
-		msg := "Failed reading \"" + vmDir + "\" in qcow (" + vmDiskFile + "): " + output
-		log.Error(msg)
+		msg := "Failed copying file to \"" + vmDir + "\" in VM"
+		log.Error(msg + ": " + output)
+		return errors.New(msg)
+	}
+	return nil
+}
+
+// Recursively downloads a directory from the VM's filesystem (vmDir) into a local tar.gz archive.
+func ArchiveFromVM(vmDiskFile, vmDir, localTarGzFile string) error {
+	cmd := exec.Command(conf.Tools.Guestfish, "--ro", "-i", "tar-out", "-a", vmDiskFile, vmDir, localTarGzFile, "compress:gzip")
+	stdoutStderr, err := cmd.CombinedOutput()
+	if err != nil {
+		output := fmt.Sprintf("[%s]", stdoutStderr)
+		msg := "Failed archiving \"" + vmDir + "\" in VM"
+		log.Error(msg + ": " + output)
+		return errors.New(msg)
+	}
+	return nil
+}
+
+// Delete a file from a VM's filesystem.
+// filePath is the full path in the VM to the file to delete.
+func DeleteFromVM(vmDiskFile, filePath string) error {
+	cmd := exec.Command(conf.Tools.Guestfish, "--rw", "-a", vmDiskFile, "-i", "rm", filePath)
+	stdoutStderr, err := cmd.CombinedOutput()
+	if err != nil {
+		output := fmt.Sprintf("[%s]", stdoutStderr)
+		msg := "Failed deleting \"" + filePath + "\" in VM"
+		log.Error(msg + ": " + output)
 		return errors.New(msg)
 	}
 	return nil
diff --git a/src/server/nexus-server.go b/src/server/nexus-server.go
index ac9436a7541f072d21d314fe5423253f76263a2c..3158f816e59ddfa9a54c96d894b49f2d64e55886 100644
--- a/src/server/nexus-server.go
+++ b/src/server/nexus-server.go
@@ -47,8 +47,17 @@ func main() {
 
 	cleaner.Start()
 
-	log.Info("Using port range [", conf.Core.VMSpiceMinPort, "-", conf.Core.VMSpiceMaxPort, "]")
+	log.Info("API port: ", conf.Core.APIDefaultPort)
+	log.Info("Spice port range [", conf.Core.VMSpiceMinPort, "-", conf.Core.VMSpiceMaxPort, "]")
 	log.Info("Tmp directory: ", conf.Core.TmpDir)
 
+	log.Info("Max upload size: ", conf.Limits.MaxUploadSize)
+	log.Info("KSM RAM saving: ", conf.Limits.KsmRamSaving*100, "%")
+	log.Info("RAM usage limit: ", conf.Limits.RamUsageLimit*100, "%")
+
+	log.Info("Max login attemps: ", conf.Auth.MaxLoginAttempts)
+	log.Info("Account lock time: ", conf.Auth.LockedTimeInHours, " hours")
+	log.Info("Access token expiration time: ", conf.Auth.AccessTokenExpirationTimeInHours, " hours")
+
 	router.New().Start(conf.Core.APIDefaultPort)
 }
diff --git a/src/server/router/routerVMs.go b/src/server/router/routerVMs.go
index 2ba356b8fb28ba73b81e996019c685cf34b262d8..0c88b380eaf8f2fc93e51522b163150cdd250f9c 100644
--- a/src/server/router/routerVMs.go
+++ b/src/server/router/routerVMs.go
@@ -6,8 +6,11 @@ import (
 	"net/http"
 	"nexus-common/caps"
 	"nexus-common/params"
+	"nexus-common/utils"
+	"nexus-server/exec"
 	"nexus-server/users"
 	"nexus-server/vms"
+
 	"os"
 	"path/filepath"
 
@@ -595,7 +598,7 @@ func (r *RouterVMs) ExportVMDir(c echo.Context) error {
 		tarGzFile := filepath.Join(conf.Core.TmpDir, "exportdir_"+vm.GetID().String()+".tar.gz")
 
 		// Extracts VM's p.Dir directory into tarGzFile on the host.
-		if err := r.vms.ExportVMFiles(vm, p.Dir, tarGzFile); err != nil {
+		if err := r.vms.ExportFilesFromVM(vm, p.Dir, tarGzFile); err != nil {
 			msg := "Failed extracting VM " + vmID + "'s dir: " + err.Error()
 			log.Error(msg)
 			return echo.NewHTTPError(http.StatusBadRequest, msg)
@@ -621,6 +624,31 @@ func (r *RouterVMs) ImportFilesToVM(c echo.Context) error {
 		// Retrieves the various client arguments.
 		vmDir := c.FormValue("vmDir")
 
+		// Checks if importing files into the VM would be successfull.
+		// The purpose of this function is to quickly checks if the import would succeed
+		// without having to wait for the archive to be uploaded from the client (which can take a while).
+		// It attempts to create an empty file inside the VM directory.
+
+		// Create a local file on the host
+		emptyLocalFile, err := utils.CreateRandomEmptyFile()
+		if err != nil {
+			return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+		}
+
+		// Remove the local file on the host when exiting the function
+		defer os.Remove(emptyLocalFile)
+
+		// Copy the local file from the host to the VM in vmDir
+		if err := r.vms.ImportFilesToVM(vm, exec.CopyToVM, emptyLocalFile, vmDir); err != nil {
+			return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+		}
+
+		// Remove the file we just copied in the VM
+		filename := filepath.Base(emptyLocalFile)
+		if err := r.vms.DeleteFileFromVM(vm, filepath.Join(vmDir, filename)); err != nil {
+			return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+		}
+
 		// Retrieves the tar.gz archive (uploadedtarGzFile).
 		tarGzFile, err := c.FormFile("file")
 		if err != nil {
@@ -652,7 +680,7 @@ func (r *RouterVMs) ImportFilesToVM(c echo.Context) error {
 
 		// Copy the archive's files into the VM
 		// IMPORTANT: the VM cannot have its disk busy
-		if err = r.vms.ImportFilesToVM(vm, uploadedtarGzFile, vmDir); err != nil {
+		if err = r.vms.ImportFilesToVM(vm, exec.DearchiveToVM, uploadedtarGzFile, vmDir); err != nil {
 			return echo.NewHTTPError(http.StatusBadRequest, err.Error())
 		}
 
diff --git a/src/server/vms/vms.go b/src/server/vms/vms.go
index 657a22e2d402a76dd7d36d117502862cc519d76a..13a6df5a33db30af2efd6b8dbc9130e0103963de 100644
--- a/src/server/vms/vms.go
+++ b/src/server/vms/vms.go
@@ -777,7 +777,7 @@ func (vms *VMs) DeleteVMAccess(vmID uuid.UUID, user *users.User, destUserEmail s
 // Technically, extracting files from a running VM should work, but some files might be inconsistent.
 // In consequence, we forbid this action on a running VM.
 // Concurrency: safe
-func (vms *VMs) ExportVMFiles(vm *VM, vmDir, tarGzFile string) error {
+func (vms *VMs) ExportFilesFromVM(vm *VM, vmDir, localTarGzFile string) error {
 	prefix := "Failed exporting files from VM: "
 
 	vm.mutex.Lock()
@@ -797,7 +797,7 @@ func (vms *VMs) ExportVMFiles(vm *VM, vmDir, tarGzFile string) error {
 
 	vmDisk := vm.getDiskPath()
 
-	if err := exec.CopyFromVM(vmDisk, vmDir, tarGzFile); err != nil {
+	if err := exec.ArchiveFromVM(vmDisk, vmDir, localTarGzFile); err != nil {
 		vm.mutex.Lock()
 		vm.DiskBusy = false
 		vm.mutex.Unlock()
@@ -815,7 +815,11 @@ func (vms *VMs) ExportVMFiles(vm *VM, vmDir, tarGzFile string) error {
 
 // Imports files from a tar.gz archive into a VM disk image (guest's filesystem), in a specified directory.
 // Concurrency: safe
-func (vms *VMs) ImportFilesToVM(vm *VM, tarGzFile, vmDir string) error {
+//func (vms *VMs) ImportFilesToVM(vm *VM, localTarGzFile, vmDir string) error {
+
+type ImportFileFunc func(vmDiskFile, localFile, vmDir string) error
+
+func (vms *VMs) ImportFilesToVM(vm *VM, fn ImportFileFunc, localFile, vmDir string) error {
 	prefix := "Failed importing files into VM: "
 
 	vm.mutex.Lock()
@@ -835,7 +839,7 @@ func (vms *VMs) ImportFilesToVM(vm *VM, tarGzFile, vmDir string) error {
 
 	vmDisk := vm.getDiskPath()
 
-	if err := exec.CopyToVM(vmDisk, tarGzFile, vmDir); err != nil {
+	if err := fn(vmDisk, localFile, vmDir); err != nil {
 		vm.mutex.Lock()
 		vm.DiskBusy = false
 		vm.mutex.Unlock()
@@ -850,3 +854,32 @@ func (vms *VMs) ImportFilesToVM(vm *VM, tarGzFile, vmDir string) error {
 
 	return nil
 }
+
+// Delete a file from a VM's filesystem.
+// filePath is the full path in the VM to the file to delete.
+func (vms *VMs) DeleteFileFromVM(vm *VM, filePath string) error {
+	prefix := "Failed deleting file from VM: "
+
+	vm.mutex.Lock()
+	defer vm.mutex.Unlock()
+
+	if vm.IsRunning() {
+		return errors.New(prefix + "VM must be stopped")
+	}
+
+	if vm.IsDiskBusy() {
+		return errors.New(prefix + "disk in use (busy)")
+	}
+
+	vm.DiskBusy = true
+	defer func(vm *VM) {
+		vm.DiskBusy = false
+	}(vm)
+
+	if err := exec.DeleteFromVM(vm.getDiskPath(), filePath); err != nil {
+		msg := prefix + err.Error()
+		log.Error(msg)
+		return errors.New(msg)
+	}
+	return nil
+}