|
@@ -58,16 +58,8 @@ export class SystemExecutors {
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- private ensureFilePermissions = async (rootFolderHost: string, logSudoRequest = true) => {
|
|
|
+ private ensureFilePermissions = async (rootFolderHost: string) => {
|
|
|
const logger = new TerminalSpinner('');
|
|
|
- // if we are running as root, we don't need to change permissions
|
|
|
- if (process.getuid && process.getuid() === 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (logSudoRequest) {
|
|
|
- logger.log('Tipi needs to change permissions on some files and folders and will ask for your password.');
|
|
|
- }
|
|
|
|
|
|
// Create group tipi if it does not exist
|
|
|
try {
|
|
@@ -106,11 +98,25 @@ export class SystemExecutors {
|
|
|
path.join(rootFolderHost, 'VERSION'),
|
|
|
];
|
|
|
|
|
|
+ const files600 = [path.join(rootFolderHost, 'traefik', 'acme.json')];
|
|
|
+
|
|
|
// Give permission to read and write to all files and folders for the current user
|
|
|
await Promise.all(
|
|
|
filesAndFolders.map(async (fileOrFolder) => {
|
|
|
if (await pathExists(fileOrFolder)) {
|
|
|
- await execAsync(`sudo chmod -R a+rwx ${fileOrFolder}`);
|
|
|
+ await execAsync(`sudo chmod -R a+rwx ${fileOrFolder}`).catch(() => {
|
|
|
+ logger.fail(`Failed to set permissions on ${fileOrFolder}`);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ );
|
|
|
+
|
|
|
+ await Promise.all(
|
|
|
+ files600.map(async (fileOrFolder) => {
|
|
|
+ if (await pathExists(fileOrFolder)) {
|
|
|
+ await execAsync(`sudo chmod 600 ${fileOrFolder}`).catch(() => {
|
|
|
+ logger.fail(`Failed to set permissions on ${fileOrFolder}`);
|
|
|
+ });
|
|
|
}
|
|
|
}),
|
|
|
);
|
|
@@ -149,15 +155,6 @@ export class SystemExecutors {
|
|
|
await appExecutor.stopApp(app, {}, true);
|
|
|
spinner.done(`${app} stopped`);
|
|
|
}
|
|
|
-
|
|
|
- await Promise.all(
|
|
|
- apps.map(async (app) => {
|
|
|
- const appSpinner = new TerminalSpinner(`Stopping ${app}...`);
|
|
|
- appSpinner.start();
|
|
|
- await appExecutor.stopApp(app, {}, true);
|
|
|
- appSpinner.done(`${app} stopped`);
|
|
|
- }),
|
|
|
- );
|
|
|
}
|
|
|
|
|
|
spinner.setMessage('Stopping containers...');
|
|
@@ -177,17 +174,37 @@ export class SystemExecutors {
|
|
|
* This method will start Tipi.
|
|
|
* It will copy the system files, generate the system env file, pull the images and start the containers.
|
|
|
*/
|
|
|
- public start = async () => {
|
|
|
+ public start = async (sudo = true) => {
|
|
|
const spinner = new TerminalSpinner('Starting Tipi...');
|
|
|
try {
|
|
|
const { isSudo } = getUserIds();
|
|
|
|
|
|
- if (!isSudo) {
|
|
|
+ if (!sudo) {
|
|
|
+ console.log(
|
|
|
+ boxen(
|
|
|
+ "You are running in sudoless mode. While Tipi should work as expected, you'll probably run into permission issues and will have to manually fix them. We recommend running Tipi with sudo for beginners.",
|
|
|
+ {
|
|
|
+ title: '⛔️Sudoless mode',
|
|
|
+ titleAlignment: 'center',
|
|
|
+ textAlignment: 'center',
|
|
|
+ padding: 1,
|
|
|
+ borderStyle: 'double',
|
|
|
+ borderColor: 'red',
|
|
|
+ margin: { top: 1, bottom: 1 },
|
|
|
+ width: 80,
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isSudo && sudo) {
|
|
|
console.log(chalk.red('Tipi needs to run as root to start. Use sudo ./runtipi-cli start'));
|
|
|
throw new Error('Tipi needs to run as root to start. Use sudo ./runtipi-cli start');
|
|
|
}
|
|
|
|
|
|
- await this.ensureFilePermissions(this.rootFolder);
|
|
|
+ if (sudo) {
|
|
|
+ await this.ensureFilePermissions(this.rootFolder);
|
|
|
+ }
|
|
|
|
|
|
spinner.start();
|
|
|
spinner.setMessage('Copying system files...');
|
|
@@ -195,7 +212,9 @@ export class SystemExecutors {
|
|
|
|
|
|
spinner.done('System files copied');
|
|
|
|
|
|
- await this.ensureFilePermissions(this.rootFolder, false);
|
|
|
+ if (sudo) {
|
|
|
+ await this.ensureFilePermissions(this.rootFolder);
|
|
|
+ }
|
|
|
|
|
|
spinner.setMessage('Generating system env file...');
|
|
|
spinner.start();
|
|
@@ -270,13 +289,19 @@ export class SystemExecutors {
|
|
|
|
|
|
spinner.done('Database migrations complete');
|
|
|
|
|
|
+ // Start all apps
|
|
|
+ const appExecutor = new AppExecutors();
|
|
|
+ await appExecutor.startAllApps();
|
|
|
+
|
|
|
console.log(
|
|
|
boxen(`Visit: http://${envMap.get('INTERNAL_IP')}:${envMap.get('NGINX_PORT')} to access the dashboard\n\nFind documentation and guides at: https://runtipi.io`, {
|
|
|
title: 'Tipi successfully started 🎉',
|
|
|
titleAlignment: 'center',
|
|
|
+ textAlignment: 'center',
|
|
|
padding: 1,
|
|
|
borderStyle: 'double',
|
|
|
borderColor: 'green',
|
|
|
+ width: 80,
|
|
|
margin: { top: 1 },
|
|
|
}),
|
|
|
);
|
|
@@ -327,7 +352,7 @@ export class SystemExecutors {
|
|
|
|
|
|
if (!targetVersion || targetVersion === 'latest') {
|
|
|
spinner.setMessage('Fetching latest version...');
|
|
|
- const { data } = await axios.get<{ tag_name: string }>('https://api.github.com/repos/meienberger/runtipi/releases');
|
|
|
+ const { data } = await axios.get<{ tag_name: string }>('https://api.github.com/repos/meienberger/runtipi/releases/latest');
|
|
|
targetVersion = data.tag_name;
|
|
|
}
|
|
|
|