fix: wp missing ftp solution
This commit is contained in:
@@ -173,6 +173,14 @@ export const wordpress = [{
|
|||||||
isNumber: false,
|
isNumber: false,
|
||||||
isBoolean: false,
|
isBoolean: false,
|
||||||
isEncrypted: false
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ftpPassword',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
}]
|
}]
|
||||||
export const ghost = [{
|
export const ghost = [{
|
||||||
name: 'defaultEmail',
|
name: 'defaultEmail',
|
||||||
|
@@ -2,9 +2,10 @@ import type { FastifyReply, FastifyRequest } from 'fastify';
|
|||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import { prisma, uniqueName, asyncExecShell, getServiceImage, getServiceImages, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePort, getDomain, errorHandler, supportedServiceTypesAndVersions } from '../../../../lib/common';
|
import { prisma, uniqueName, asyncExecShell, getServiceImage, getServiceImages, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePort, getDomain, errorHandler, supportedServiceTypesAndVersions, generatePassword, isDev, stopTcpHttpProxy } from '../../../../lib/common';
|
||||||
import { day } from '../../../../lib/dayjs';
|
import { day } from '../../../../lib/dayjs';
|
||||||
import { checkContainer, dockerInstance, getEngine, removeContainer } from '../../../../lib/docker';
|
import { checkContainer, dockerInstance, getEngine, removeContainer } from '../../../../lib/docker';
|
||||||
|
import cuid from 'cuid';
|
||||||
|
|
||||||
export async function listServices(request: FastifyRequest) {
|
export async function listServices(request: FastifyRequest) {
|
||||||
try {
|
try {
|
||||||
@@ -259,7 +260,7 @@ export async function checkService(request: FastifyRequest) {
|
|||||||
exposePort = Number(exposePort);
|
exposePort = Number(exposePort);
|
||||||
|
|
||||||
if (exposePort < 1024 || exposePort > 65535) {
|
if (exposePort < 1024 || exposePort > 65535) {
|
||||||
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
|
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
|
||||||
}
|
}
|
||||||
|
|
||||||
const publicPort = await getPort({ port: exposePort });
|
const publicPort = await getPort({ port: exposePort });
|
||||||
@@ -2416,4 +2417,163 @@ export async function activatePlausibleUsers(request: FastifyRequest, reply: Fas
|
|||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function activateWordpressFtp(request: FastifyRequest, reply: FastifyReply) {
|
||||||
|
const { id } = request.params
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
|
||||||
|
const { ftpEnabled } = request.body;
|
||||||
|
|
||||||
|
const publicPort = await getFreePort();
|
||||||
|
let ftpUser = cuid();
|
||||||
|
let ftpPassword = generatePassword();
|
||||||
|
|
||||||
|
const hostkeyDir = isDev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
|
||||||
|
try {
|
||||||
|
const data = await prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpEnabled },
|
||||||
|
include: { service: { include: { destinationDocker: true } } }
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
service: { destinationDockerId, destinationDocker },
|
||||||
|
ftpPublicPort,
|
||||||
|
ftpUser: user,
|
||||||
|
ftpPassword: savedPassword,
|
||||||
|
ftpHostKey,
|
||||||
|
ftpHostKeyPrivate
|
||||||
|
} = data;
|
||||||
|
const { network, engine } = destinationDocker;
|
||||||
|
const host = getEngine(engine);
|
||||||
|
if (ftpEnabled) {
|
||||||
|
if (user) ftpUser = user;
|
||||||
|
if (savedPassword) ftpPassword = decrypt(savedPassword);
|
||||||
|
|
||||||
|
const { stdout: password } = await asyncExecShell(
|
||||||
|
`echo ${ftpPassword} | openssl passwd -1 -stdin`
|
||||||
|
);
|
||||||
|
if (destinationDockerId) {
|
||||||
|
try {
|
||||||
|
await fs.stat(hostkeyDir);
|
||||||
|
} catch (error) {
|
||||||
|
await asyncExecShell(`mkdir -p ${hostkeyDir}`);
|
||||||
|
}
|
||||||
|
if (!ftpHostKey) {
|
||||||
|
await asyncExecShell(
|
||||||
|
`ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
|
||||||
|
);
|
||||||
|
const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`);
|
||||||
|
await prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpHostKey: encrypt(ftpHostKey) }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`);
|
||||||
|
}
|
||||||
|
if (!ftpHostKeyPrivate) {
|
||||||
|
await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`);
|
||||||
|
const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`);
|
||||||
|
await prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: {
|
||||||
|
ftpPublicPort: publicPort,
|
||||||
|
ftpUser: user ? undefined : ftpUser,
|
||||||
|
ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const isRunning = await checkContainer(engine, `${id}-ftp`);
|
||||||
|
if (isRunning) {
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
const volumes = [
|
||||||
|
`${id}-wordpress-data:/home/${ftpUser}`,
|
||||||
|
`${isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
|
||||||
|
`${isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
|
||||||
|
`${isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.sh:/etc/sftp.d/chmod.sh`
|
||||||
|
];
|
||||||
|
|
||||||
|
const compose: ComposeFile = {
|
||||||
|
version: '3.8',
|
||||||
|
services: {
|
||||||
|
[`${id}-ftp`]: {
|
||||||
|
image: `atmoz/sftp:alpine`,
|
||||||
|
command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
|
||||||
|
extra_hosts: ['host.docker.internal:host-gateway'],
|
||||||
|
container_name: `${id}-ftp`,
|
||||||
|
volumes,
|
||||||
|
networks: [network],
|
||||||
|
depends_on: [],
|
||||||
|
restart: 'always'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
networks: {
|
||||||
|
[network]: {
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
volumes: {
|
||||||
|
[`${id}-wordpress-data`]: {
|
||||||
|
external: true,
|
||||||
|
name: `${id}-wordpress-data`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await fs.writeFile(
|
||||||
|
`${hostkeyDir}/${id}.sh`,
|
||||||
|
`#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key`
|
||||||
|
);
|
||||||
|
await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`);
|
||||||
|
await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return reply.code(201).send({
|
||||||
|
publicPort,
|
||||||
|
ftpUser,
|
||||||
|
ftpPassword
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpPublicPort: null }
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
await stopTcpHttpProxy(id, destinationDocker, ftpPublicPort);
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
} finally {
|
||||||
|
await asyncExecShell(
|
||||||
|
`rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import {
|
import {
|
||||||
activatePlausibleUsers,
|
activatePlausibleUsers,
|
||||||
|
activateWordpressFtp,
|
||||||
checkService,
|
checkService,
|
||||||
deleteService,
|
deleteService,
|
||||||
deleteServiceSecret,
|
deleteServiceSecret,
|
||||||
@@ -65,6 +66,7 @@ const root: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
|||||||
fastify.post('/:id/:type/settings', async (request, reply) => await setSettingsService(request, reply));
|
fastify.post('/:id/:type/settings', async (request, reply) => await setSettingsService(request, reply));
|
||||||
|
|
||||||
fastify.post('/:id/plausibleanalytics/activate', async (request, reply) => await activatePlausibleUsers(request, reply));
|
fastify.post('/:id/plausibleanalytics/activate', async (request, reply) => await activatePlausibleUsers(request, reply));
|
||||||
|
fastify.post('/:id/wordpress/ftp', async (request, reply) => await activateWordpressFtp(request, reply));
|
||||||
};
|
};
|
||||||
|
|
||||||
export default root;
|
export default root;
|
||||||
|
@@ -112,7 +112,7 @@ define('SUBDOMAIN_INSTALL', false);`
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="ftpPassword">Password</label>
|
<label for="ftpPassword">Password</label>
|
||||||
<CopyPasswordField id="ftpPassword" readonly disabled name="ftpPassword" value={ftpPassword} />
|
<CopyPasswordField id="ftpPassword" isPasswordField readonly disabled name="ftpPassword" value={ftpPassword} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex space-x-1 py-5 font-bold">
|
<div class="flex space-x-1 py-5 font-bold">
|
||||||
|
Reference in New Issue
Block a user