cloudron 8.0.0 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cloudron +13 -2
- package/package.json +1 -1
- package/src/actions.js +105 -34
- package/src/helper.js +5 -3
- package/src/templates/flask/CloudronManifest.json +25 -0
- package/src/templates/flask/Dockerfile +16 -0
- package/src/templates/flask/app/__init__.py +5 -0
- package/src/templates/flask/app/views.py +5 -0
- package/src/templates/flask/dockerignore +5 -0
- package/src/templates/flask/requirements.txt +1 -0
- package/src/templates/flask/run.py +4 -0
- package/src/templates/flask/start.sh +8 -0
- package/src/templates/flask/supervisor/uwsgi.conf +12 -0
- package/src/templates/flask/template.json +3 -0
- package/src/templates/flask/uwsgi.ini +6 -0
- package/src/templates/lamp/CloudronManifest.json +26 -0
- package/src/templates/lamp/Dockerfile +27 -0
- package/src/templates/lamp/apache/app.conf +17 -0
- package/src/templates/lamp/apache/mpm_prefork.conf +7 -0
- package/src/templates/lamp/dockerignore +4 -0
- package/src/templates/lamp/index.php +18 -0
- package/src/templates/lamp/start.sh +9 -0
- package/src/templates/lamp/template.json +3 -0
- package/src/templates/lamp-composer/CloudronManifest.json +26 -0
- package/src/templates/lamp-composer/Dockerfile +30 -0
- package/src/templates/lamp-composer/apache/app.conf +17 -0
- package/src/templates/lamp-composer/apache/mpm_prefork.conf +7 -0
- package/src/templates/lamp-composer/composer.json +8 -0
- package/src/templates/lamp-composer/dockerignore +5 -0
- package/src/templates/lamp-composer/public/index.php +20 -0
- package/src/templates/lamp-composer/start.sh +9 -0
- package/src/templates/lamp-composer/template.json +3 -0
- package/src/templates/lemp/CloudronManifest.json +26 -0
- package/src/templates/lemp/Dockerfile +27 -0
- package/src/templates/lemp/dockerignore +4 -0
- package/src/templates/lemp/index.php +18 -0
- package/src/templates/lemp/nginx/app.conf +22 -0
- package/src/templates/lemp/start.sh +11 -0
- package/src/templates/lemp/template.json +3 -0
- package/src/templates/nextjs/CloudronManifest.json +25 -0
- package/src/templates/nextjs/Dockerfile +14 -0
- package/src/templates/nextjs/app/layout.js +12 -0
- package/src/templates/nextjs/app/page.js +7 -0
- package/src/templates/nextjs/dockerignore +5 -0
- package/src/templates/nextjs/next.config.mjs +6 -0
- package/src/templates/nextjs/package.json +15 -0
- package/src/templates/nextjs/start.sh +9 -0
- package/src/templates/nextjs/template.json +3 -0
- package/src/templates/nodejs/CloudronManifest.json +25 -0
- package/src/templates/nodejs/Dockerfile +10 -0
- package/src/templates/nodejs/dockerignore +4 -0
- package/src/templates/nodejs/package.json +11 -0
- package/src/templates/nodejs/server.js +12 -0
- package/src/templates/nodejs/start.sh +9 -0
- package/src/templates/nodejs/template.json +3 -0
- package/src/templates/nodejs-mongodb/CloudronManifest.json +26 -0
- package/src/templates/nodejs-mongodb/Dockerfile +10 -0
- package/src/templates/nodejs-mongodb/dockerignore +4 -0
- package/src/templates/nodejs-mongodb/package.json +14 -0
- package/src/templates/nodejs-mongodb/server.js +24 -0
- package/src/templates/nodejs-mongodb/start.sh +9 -0
- package/src/templates/nodejs-mongodb/template.json +3 -0
- package/src/templates/rails/CloudronManifest.json +26 -0
- package/src/templates/rails/Dockerfile +16 -0
- package/src/templates/rails/Gemfile +5 -0
- package/src/templates/rails/config/database.yml +4 -0
- package/src/templates/rails/config/puma.rb +9 -0
- package/src/templates/rails/dockerignore +7 -0
- package/src/templates/rails/public/index.html +12 -0
- package/src/templates/rails/start.sh +14 -0
- package/src/templates/rails/supervisor/puma.conf +12 -0
- package/src/templates/rails/template.json +3 -0
- package/src/templates/static/CloudronManifest.json +25 -0
- package/src/templates/static/Dockerfile +17 -0
- package/src/templates/static/apache/app.conf +13 -0
- package/src/templates/static/apache/mpm_prefork.conf +7 -0
- package/src/templates/static/dockerignore +3 -0
- package/src/templates/static/public/index.html +11 -0
- package/src/templates/static/start.sh +7 -0
- package/src/templates/static/template.json +3 -0
- package/test/test.js +1 -1
- /package/src/templates/{CloudronManifest.appstore.json.ejs → default/CloudronManifest.json.ejs} +0 -0
- /package/src/templates/{CloudronManifest.json.ejs → default/CloudronManifest.minimal.json.ejs} +0 -0
- /package/src/templates/{Dockerfile.ejs → default/Dockerfile.ejs} +0 -0
- /package/src/templates/{dockerignore.ejs → default/dockerignore.ejs} +0 -0
- /package/src/templates/{start.sh.ejs → default/start.sh.ejs} +0 -0
package/bin/cloudron
CHANGED
|
@@ -91,7 +91,7 @@ const buildCommand = program.command('build').description('Build using the build
|
|
|
91
91
|
.option('--build-service-url <url>', 'Build service URL')
|
|
92
92
|
.option('--build-service-token <token>', 'Build service token');
|
|
93
93
|
|
|
94
|
-
buildCommand.command('build', { isDefault: true })
|
|
94
|
+
const buildBuildCommand = buildCommand.command('build', { isDefault: true })
|
|
95
95
|
.description('Build an app')
|
|
96
96
|
.option('--build-arg <namevalue>', 'Build arg passed to docker. Can be used multiple times', collectBuildArgs, [])
|
|
97
97
|
.option('-f, --file <dockerfile>', 'Name of the Dockerfile')
|
|
@@ -137,6 +137,11 @@ buildCommand.command('status')
|
|
|
137
137
|
.option('--id <buildid>', 'Build ID')
|
|
138
138
|
.action(buildActions.status);
|
|
139
139
|
|
|
140
|
+
buildCommand.addHelpText('after', (ctx) => {
|
|
141
|
+
const header = '\nDefault subcommand `build` (same as `cloudron build build`; used when no subcommand is given):\n\n';
|
|
142
|
+
return header + buildBuildCommand.helpInformation({ error: ctx.error });
|
|
143
|
+
});
|
|
144
|
+
|
|
140
145
|
backupCommand.command('create')
|
|
141
146
|
.description('Create new app backup')
|
|
142
147
|
.option('--site <siteid>', 'App id')
|
|
@@ -259,7 +264,9 @@ program.command('inspect')
|
|
|
259
264
|
|
|
260
265
|
program.command('init')
|
|
261
266
|
.description('Creates a new CloudronManifest.json and Dockerfile')
|
|
262
|
-
.option('--
|
|
267
|
+
.option('--minimal', 'Minimal template')
|
|
268
|
+
.option('--template <name>', 'Use a project template (use --list-templates to see all)')
|
|
269
|
+
.option('--list-templates', 'List available templates')
|
|
263
270
|
.action(actions.init);
|
|
264
271
|
|
|
265
272
|
program.command('install')
|
|
@@ -276,6 +283,8 @@ program.command('install')
|
|
|
276
283
|
.option('--debug [cmd...]', 'Enable debug mode', false)
|
|
277
284
|
.option('--readonly', 'Mount filesystem readonly. Default is read/write in debug mode.')
|
|
278
285
|
.option('--env <KEY=value...>', 'Set environment variables. e.g X=1 Y=2')
|
|
286
|
+
.option('--build-arg <namevalue>', 'Build arg passed to docker. Can be used multiple times', collectBuildArgs, [])
|
|
287
|
+
.option('-f, --file <dockerfile>', 'Name of the Dockerfile')
|
|
279
288
|
.action(actions.install);
|
|
280
289
|
|
|
281
290
|
program.command('list')
|
|
@@ -400,6 +409,8 @@ program.command('update')
|
|
|
400
409
|
.option('--image <docker image>', 'Docker image')
|
|
401
410
|
.option('--no-backup', 'Skip backup [false]')
|
|
402
411
|
.option('--no-force', 'Match appstore id and manifest id before updating', true)
|
|
412
|
+
.option('--build-arg <namevalue>', 'Build arg passed to docker. Can be used multiple times', collectBuildArgs, [])
|
|
413
|
+
.option('-f, --file <dockerfile>', 'Name of the Dockerfile')
|
|
403
414
|
.action(actions.update);
|
|
404
415
|
|
|
405
416
|
const versionsCommand = program.command('versions').description('Commands for publishing community packages');
|
package/package.json
CHANGED
package/src/actions.js
CHANGED
|
@@ -224,7 +224,7 @@ async function waitForFinishInstallation(appId, taskId, options) {
|
|
|
224
224
|
|
|
225
225
|
if (response.body.installationState !== 'installed') throw new Error(`Installation failed: ${response.body.error ? response.body.error.message : ''}`);
|
|
226
226
|
|
|
227
|
-
await waitForHealthy(appId, options);
|
|
227
|
+
if (!options.debug) await waitForHealthy(appId, options);
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
async function waitForFinishBackup(appId, taskId, options) {
|
|
@@ -347,6 +347,7 @@ async function login(adminFqdn, localOptions, cmd) {
|
|
|
347
347
|
|
|
348
348
|
if (semver.gte(response.body.version, '9.1.0')) {
|
|
349
349
|
token = await performOidcLogin(adminFqdn, { rejectUnauthorized });
|
|
350
|
+
if (!token) process.exit(1);
|
|
350
351
|
} else {
|
|
351
352
|
const username = options.username || await readline.question('Username: ', {});
|
|
352
353
|
const password = options.password || await readline.question('Password: ', { noEchoBack: true });
|
|
@@ -682,7 +683,6 @@ async function install(localOptions, cmd) {
|
|
|
682
683
|
cmd: debugCmd
|
|
683
684
|
};
|
|
684
685
|
data.memoryLimit = -1;
|
|
685
|
-
options.wait = false; // in debug mode, health check never succeeds
|
|
686
686
|
}
|
|
687
687
|
|
|
688
688
|
if (!options.appstoreId && !options.versionsUrl && manifest && manifest.icon) {
|
|
@@ -711,6 +711,10 @@ async function install(localOptions, cmd) {
|
|
|
711
711
|
if (data.sso !== undefined) request.field('sso', String(data.sso));
|
|
712
712
|
if (data.debugMode) request.field('debugMode', JSON.stringify(data.debugMode));
|
|
713
713
|
if (data.icon) request.field('icon', data.icon);
|
|
714
|
+
const buildConfig = {};
|
|
715
|
+
if (options.buildArg && options.buildArg.length) buildConfig.buildArgs = options.buildArg;
|
|
716
|
+
if (options.file) buildConfig.dockerfileName = options.file;
|
|
717
|
+
if (Object.keys(buildConfig).length) request.field('buildConfig', JSON.stringify(buildConfig));
|
|
714
718
|
request.attach('sourceArchive', sourceArchiveFilePath);
|
|
715
719
|
|
|
716
720
|
response = await request;
|
|
@@ -902,6 +906,10 @@ async function update(localOptions, cmd) {
|
|
|
902
906
|
request.field('skipNotification', String(data.skipNotification));
|
|
903
907
|
request.field('force', String(data.force));
|
|
904
908
|
if (data.icon) request.field('icon', data.icon);
|
|
909
|
+
const buildConfig = {};
|
|
910
|
+
if (options.buildArg && options.buildArg.length) buildConfig.buildArgs = options.buildArg;
|
|
911
|
+
if (options.file) buildConfig.dockerfileName = options.file;
|
|
912
|
+
if (Object.keys(buildConfig).length) request.field('buildConfig', JSON.stringify(buildConfig));
|
|
905
913
|
request.attach('sourceArchive', sourceArchiveFilePath);
|
|
906
914
|
|
|
907
915
|
response = await request;
|
|
@@ -1503,7 +1511,6 @@ function runExecSession(appId, execId, { stdin, stdout, stderr, tty }, options)
|
|
|
1503
1511
|
if (stdout !== process.stdout && typeof stdout.end === 'function') {
|
|
1504
1512
|
stdout.on('close', () => resolve());
|
|
1505
1513
|
stdout.end();
|
|
1506
|
-
stdout.resume(); // drain readable side of Duplex/Transform streams so autoDestroy emits 'close'
|
|
1507
1514
|
} else {
|
|
1508
1515
|
setImmediate(resolve);
|
|
1509
1516
|
}
|
|
@@ -1911,52 +1918,116 @@ async function syncPull(remoteDir, localDir, localOptions, cmd) {
|
|
|
1911
1918
|
}
|
|
1912
1919
|
}
|
|
1913
1920
|
|
|
1921
|
+
function listTemplates() {
|
|
1922
|
+
const templatesDir = path.join(import.meta.dirname, 'templates');
|
|
1923
|
+
const entries = fs.readdirSync(templatesDir, { withFileTypes: true });
|
|
1924
|
+
|
|
1925
|
+
console.log();
|
|
1926
|
+
console.log('Available templates:');
|
|
1927
|
+
console.log();
|
|
1928
|
+
|
|
1929
|
+
for (const entry of entries) {
|
|
1930
|
+
if (!entry.isDirectory()) continue;
|
|
1931
|
+
|
|
1932
|
+
const metaPath = path.join(templatesDir, entry.name, 'template.json');
|
|
1933
|
+
if (!fs.existsSync(metaPath)) continue;
|
|
1934
|
+
|
|
1935
|
+
const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
1936
|
+
console.log(` ${entry.name.padEnd(15)} ${meta.description}`);
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
console.log();
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
function copyTemplateDir(srcDir, destDir) {
|
|
1943
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
1944
|
+
|
|
1945
|
+
for (const entry of entries) {
|
|
1946
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
1947
|
+
|
|
1948
|
+
if (entry.name === 'template.json') continue;
|
|
1949
|
+
|
|
1950
|
+
const destName = entry.name === 'dockerignore' ? '.dockerignore' : entry.name;
|
|
1951
|
+
const destPath = path.join(destDir, destName);
|
|
1952
|
+
|
|
1953
|
+
if (entry.isDirectory()) {
|
|
1954
|
+
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
|
|
1955
|
+
copyTemplateDir(srcPath, destPath);
|
|
1956
|
+
} else {
|
|
1957
|
+
if (fs.existsSync(destPath)) {
|
|
1958
|
+
console.log(`${destName} already exists, skipping`);
|
|
1959
|
+
continue;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1963
|
+
|
|
1964
|
+
if (destName === 'start.sh') fs.chmodSync(destPath, 0o0775);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1914
1969
|
function init(localOptions, cmd) {
|
|
1915
1970
|
const options = cmd.optsWithGlobals();
|
|
1971
|
+
|
|
1972
|
+
if (options.listTemplates) return listTemplates();
|
|
1973
|
+
|
|
1974
|
+
if (options.template && options.minimal) return exit('--template and --minimal are mutually exclusive');
|
|
1975
|
+
|
|
1916
1976
|
const manifestFilePath = locateManifest();
|
|
1917
1977
|
if (manifestFilePath && path.dirname(manifestFilePath) === process.cwd()) return exit('CloudronManifest.json already exists in current directory');
|
|
1918
1978
|
|
|
1919
|
-
|
|
1979
|
+
if (options.template) {
|
|
1980
|
+
const templateDir = path.join(import.meta.dirname, 'templates', options.template);
|
|
1981
|
+
const metaPath = path.join(templateDir, 'template.json');
|
|
1982
|
+
if (!fs.existsSync(metaPath)) {
|
|
1983
|
+
console.log(`Unknown template "${options.template}".`);
|
|
1984
|
+
return listTemplates();
|
|
1985
|
+
}
|
|
1920
1986
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
const startShTemplate = fs.readFileSync(path.join(import.meta.dirname, 'templates/', 'start.sh.ejs'), 'utf8');
|
|
1987
|
+
copyTemplateDir(templateDir, process.cwd());
|
|
1988
|
+
} else {
|
|
1989
|
+
const manifestTemplateFilename = !options.minimal ? 'CloudronManifest.json.ejs' : 'CloudronManifest.minimal.json.ejs';
|
|
1925
1990
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
};
|
|
1991
|
+
const manifestTemplate = fs.readFileSync(path.join(import.meta.dirname, 'templates/default/', manifestTemplateFilename), 'utf8');
|
|
1992
|
+
const dockerfileTemplate = fs.readFileSync(path.join(import.meta.dirname, 'templates/default/', 'Dockerfile.ejs'), 'utf8');
|
|
1993
|
+
const dockerignoreTemplate = fs.readFileSync(path.join(import.meta.dirname, 'templates/default/', 'dockerignore.ejs'), 'utf8');
|
|
1994
|
+
const startShTemplate = fs.readFileSync(path.join(import.meta.dirname, 'templates/default/', 'start.sh.ejs'), 'utf8');
|
|
1931
1995
|
|
|
1932
|
-
|
|
1933
|
-
|
|
1996
|
+
const data = {
|
|
1997
|
+
version: '0.1.0',
|
|
1998
|
+
title: 'App title',
|
|
1999
|
+
httpPort: 3000
|
|
2000
|
+
};
|
|
1934
2001
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
} else {
|
|
1938
|
-
const dockerfile = ejs.render(dockerfileTemplate, data);
|
|
1939
|
-
fs.writeFileSync('Dockerfile', dockerfile, 'utf8');
|
|
1940
|
-
}
|
|
2002
|
+
const manifest = ejs.render(manifestTemplate, data);
|
|
2003
|
+
fs.writeFileSync('CloudronManifest.json', manifest, 'utf8');
|
|
1941
2004
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
2005
|
+
if (fs.existsSync('Dockerfile')) {
|
|
2006
|
+
console.log('Dockerfile already exists, skipping');
|
|
2007
|
+
} else {
|
|
2008
|
+
const dockerfile = ejs.render(dockerfileTemplate, data);
|
|
2009
|
+
fs.writeFileSync('Dockerfile', dockerfile, 'utf8');
|
|
2010
|
+
}
|
|
1948
2011
|
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2012
|
+
if (fs.existsSync('.dockerignore')) {
|
|
2013
|
+
console.log('.dockerignore already exists, skipping');
|
|
2014
|
+
} else {
|
|
2015
|
+
const dockerignore = ejs.render(dockerignoreTemplate, data);
|
|
2016
|
+
fs.writeFileSync('.dockerignore', dockerignore, 'utf8');
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
if (fs.existsSync('start.sh')) {
|
|
2020
|
+
console.log('start.sh already exists, skipping');
|
|
2021
|
+
} else {
|
|
2022
|
+
const startSh = ejs.render(startShTemplate, {});
|
|
2023
|
+
fs.writeFileSync('start.sh', startSh, 'utf8');
|
|
2024
|
+
fs.chmodSync('start.sh', 0o0775);
|
|
2025
|
+
}
|
|
1955
2026
|
}
|
|
1956
2027
|
|
|
1957
2028
|
fs.copyFileSync(path.join(import.meta.dirname, 'templates/', 'logo.png'), 'logo.png');
|
|
1958
2029
|
|
|
1959
|
-
if (options.
|
|
2030
|
+
if (!options.minimal) {
|
|
1960
2031
|
if (!fs.existsSync('.gitignore')) fs.writeFileSync('.gitignore', 'node_modules/\n', 'utf8');
|
|
1961
2032
|
if (!fs.existsSync('DESCRIPTION.md')) fs.writeFileSync('DESCRIPTION.md', '## About\n\nThis app changes everything\n\n', 'utf8');
|
|
1962
2033
|
if (!fs.existsSync('POSTINSTALL.md')) fs.writeFileSync('POSTINSTALL.md', 'Post installation information\n\n', 'utf8');
|
package/src/helper.js
CHANGED
|
@@ -87,7 +87,7 @@ async function performOidcLogin(adminFqdn, { rejectUnauthorized = true } = {}) {
|
|
|
87
87
|
|
|
88
88
|
const { device_code, user_code, verification_uri_complete, verification_uri, interval: pollInterval = 5 } = deviceResponse.body;
|
|
89
89
|
|
|
90
|
-
console.log(`\nOpen ${verification_uri_complete || verification_uri} in a browser and
|
|
90
|
+
console.log(`\nOpen ${verification_uri_complete || verification_uri} in a browser and confirm code: ${user_code}\n`);
|
|
91
91
|
|
|
92
92
|
// try to open browser automatically
|
|
93
93
|
safe(open(verification_uri_complete || verification_uri));
|
|
@@ -119,10 +119,12 @@ async function performOidcLogin(adminFqdn, { rejectUnauthorized = true } = {}) {
|
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
console.log('Login failed. Try again.');
|
|
123
|
+
return null;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
console.log('Login timed out. Try again.');
|
|
127
|
+
return null;
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
export {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"upstreamVersion": "",
|
|
5
|
+
"minBoxVersion": "9.0.0",
|
|
6
|
+
"title": "",
|
|
7
|
+
"author": "",
|
|
8
|
+
"description": "file://DESCRIPTION.md",
|
|
9
|
+
"tagline": "",
|
|
10
|
+
"website": "",
|
|
11
|
+
"contactEmail": "",
|
|
12
|
+
"iconUrl": "file://logo.png",
|
|
13
|
+
"healthCheckPath": "/",
|
|
14
|
+
"mediaLinks": [],
|
|
15
|
+
"httpPort": 3000,
|
|
16
|
+
"tags": [],
|
|
17
|
+
"changelog": "file://CHANGELOG",
|
|
18
|
+
"postInstallMessage": "file://POSTINSTALL.md",
|
|
19
|
+
"documentationUrl": "",
|
|
20
|
+
"forumUrl": "",
|
|
21
|
+
"addons": {
|
|
22
|
+
"localstorage": {}
|
|
23
|
+
},
|
|
24
|
+
"manifestVersion": 2
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
|
2
|
+
|
|
3
|
+
RUN mkdir -p /app/code
|
|
4
|
+
WORKDIR /app/code
|
|
5
|
+
|
|
6
|
+
COPY . /app/code
|
|
7
|
+
|
|
8
|
+
RUN pip install -r requirements.txt
|
|
9
|
+
|
|
10
|
+
ADD supervisor/* /etc/supervisor/conf.d/
|
|
11
|
+
RUN ln -sf /run/supervisord.log /var/log/supervisor/supervisord.log
|
|
12
|
+
|
|
13
|
+
ADD uwsgi.ini /etc/uwsgi/apps-available/flask-uwsgi.ini
|
|
14
|
+
RUN ln -s /etc/uwsgi/apps-available/flask-uwsgi.ini /etc/uwsgi/apps-enabled/flask-uwsgi.ini
|
|
15
|
+
|
|
16
|
+
CMD ["/app/code/start.sh"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flask
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[program:uwsgi]
|
|
2
|
+
autorestart=true
|
|
3
|
+
autostart=true
|
|
4
|
+
command=uwsgi --master --workers 2 --no-orphans --ini /etc/uwsgi/apps-enabled/flask-uwsgi.ini
|
|
5
|
+
stdout_logfile=/dev/stdout
|
|
6
|
+
stdout_logfile_maxbytes=0
|
|
7
|
+
stderr_logfile=/dev/stderr
|
|
8
|
+
stderr_logfile_maxbytes=0
|
|
9
|
+
killasgroup=true
|
|
10
|
+
stopasgroup=true
|
|
11
|
+
stopsignal=QUIT
|
|
12
|
+
priority=100
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"upstreamVersion": "",
|
|
5
|
+
"minBoxVersion": "9.0.0",
|
|
6
|
+
"title": "",
|
|
7
|
+
"author": "",
|
|
8
|
+
"description": "file://DESCRIPTION.md",
|
|
9
|
+
"tagline": "",
|
|
10
|
+
"website": "",
|
|
11
|
+
"contactEmail": "",
|
|
12
|
+
"iconUrl": "file://logo.png",
|
|
13
|
+
"healthCheckPath": "/",
|
|
14
|
+
"mediaLinks": [],
|
|
15
|
+
"httpPort": 3000,
|
|
16
|
+
"tags": [],
|
|
17
|
+
"changelog": "file://CHANGELOG",
|
|
18
|
+
"postInstallMessage": "file://POSTINSTALL.md",
|
|
19
|
+
"documentationUrl": "",
|
|
20
|
+
"forumUrl": "",
|
|
21
|
+
"addons": {
|
|
22
|
+
"localstorage": {},
|
|
23
|
+
"mysql": {}
|
|
24
|
+
},
|
|
25
|
+
"manifestVersion": 2
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
|
2
|
+
|
|
3
|
+
RUN mkdir -p /app/code
|
|
4
|
+
WORKDIR /app/code
|
|
5
|
+
|
|
6
|
+
RUN rm /etc/apache2/sites-enabled/*
|
|
7
|
+
RUN sed -e 's,^ErrorLog.*,ErrorLog "|/bin/cat",' -i /etc/apache2/apache2.conf
|
|
8
|
+
COPY apache/mpm_prefork.conf /etc/apache2/mods-available/mpm_prefork.conf
|
|
9
|
+
|
|
10
|
+
RUN a2disconf other-vhosts-access-log
|
|
11
|
+
COPY apache/app.conf /etc/apache2/sites-enabled/app.conf
|
|
12
|
+
RUN echo "Listen 3000" > /etc/apache2/ports.conf
|
|
13
|
+
|
|
14
|
+
RUN a2enmod php8.3
|
|
15
|
+
RUN crudini --set /etc/php/8.3/apache2/php.ini PHP upload_max_filesize 256M && \
|
|
16
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP upload_max_size 256M && \
|
|
17
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP post_max_size 256M && \
|
|
18
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP memory_limit 256M && \
|
|
19
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP max_execution_time 200 && \
|
|
20
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.save_path /run/app/sessions && \
|
|
21
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.gc_probability 1 && \
|
|
22
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.gc_divisor 100
|
|
23
|
+
|
|
24
|
+
COPY index.php start.sh /app/code/
|
|
25
|
+
RUN chown -R www-data.www-data /app/code
|
|
26
|
+
|
|
27
|
+
CMD [ "/app/code/start.sh" ]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<VirtualHost *:3000>
|
|
2
|
+
DocumentRoot /app/code
|
|
3
|
+
|
|
4
|
+
ErrorLog "|/bin/cat"
|
|
5
|
+
CustomLog "|/bin/cat" combined
|
|
6
|
+
|
|
7
|
+
<Directory /app/code/>
|
|
8
|
+
Options +FollowSymLinks
|
|
9
|
+
AllowOverride All
|
|
10
|
+
Require all granted
|
|
11
|
+
|
|
12
|
+
<Files "config.php">
|
|
13
|
+
Require all denied
|
|
14
|
+
</Files>
|
|
15
|
+
</Directory>
|
|
16
|
+
|
|
17
|
+
</VirtualHost>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
$host = getenv("CLOUDRON_MYSQL_HOST");
|
|
3
|
+
$port = getenv("CLOUDRON_MYSQL_PORT");
|
|
4
|
+
$username = getenv("CLOUDRON_MYSQL_USERNAME");
|
|
5
|
+
$password = getenv("CLOUDRON_MYSQL_PASSWORD");
|
|
6
|
+
$database = getenv("CLOUDRON_MYSQL_DATABASE");
|
|
7
|
+
|
|
8
|
+
echo "<h1>Hello from Cloudron!</h1>\n";
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
$dsn = "mysql:host=$host;port=$port;dbname=$database";
|
|
12
|
+
$pdo = new PDO($dsn, $username, $password);
|
|
13
|
+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
14
|
+
echo "<p>MySQL connection successful.</p>\n";
|
|
15
|
+
} catch (PDOException $e) {
|
|
16
|
+
echo "<p>MySQL connection failed: " . htmlspecialchars($e->getMessage()) . "</p>\n";
|
|
17
|
+
}
|
|
18
|
+
?>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"upstreamVersion": "",
|
|
5
|
+
"minBoxVersion": "9.0.0",
|
|
6
|
+
"title": "",
|
|
7
|
+
"author": "",
|
|
8
|
+
"description": "file://DESCRIPTION.md",
|
|
9
|
+
"tagline": "",
|
|
10
|
+
"website": "",
|
|
11
|
+
"contactEmail": "",
|
|
12
|
+
"iconUrl": "file://logo.png",
|
|
13
|
+
"healthCheckPath": "/",
|
|
14
|
+
"mediaLinks": [],
|
|
15
|
+
"httpPort": 3000,
|
|
16
|
+
"tags": [],
|
|
17
|
+
"changelog": "file://CHANGELOG",
|
|
18
|
+
"postInstallMessage": "file://POSTINSTALL.md",
|
|
19
|
+
"documentationUrl": "",
|
|
20
|
+
"forumUrl": "",
|
|
21
|
+
"addons": {
|
|
22
|
+
"localstorage": {},
|
|
23
|
+
"mysql": {}
|
|
24
|
+
},
|
|
25
|
+
"manifestVersion": 2
|
|
26
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
|
2
|
+
|
|
3
|
+
RUN mkdir -p /app/code
|
|
4
|
+
WORKDIR /app/code
|
|
5
|
+
|
|
6
|
+
RUN rm /etc/apache2/sites-enabled/*
|
|
7
|
+
RUN sed -e 's,^ErrorLog.*,ErrorLog "|/bin/cat",' -i /etc/apache2/apache2.conf
|
|
8
|
+
COPY apache/mpm_prefork.conf /etc/apache2/mods-available/mpm_prefork.conf
|
|
9
|
+
|
|
10
|
+
RUN a2disconf other-vhosts-access-log
|
|
11
|
+
COPY apache/app.conf /etc/apache2/sites-enabled/app.conf
|
|
12
|
+
RUN echo "Listen 3000" > /etc/apache2/ports.conf
|
|
13
|
+
|
|
14
|
+
RUN a2enmod php8.3 rewrite
|
|
15
|
+
RUN crudini --set /etc/php/8.3/apache2/php.ini PHP upload_max_filesize 256M && \
|
|
16
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP upload_max_size 256M && \
|
|
17
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP post_max_size 256M && \
|
|
18
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP memory_limit 256M && \
|
|
19
|
+
crudini --set /etc/php/8.3/apache2/php.ini PHP max_execution_time 200 && \
|
|
20
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.save_path /run/app/sessions && \
|
|
21
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.gc_probability 1 && \
|
|
22
|
+
crudini --set /etc/php/8.3/apache2/php.ini Session session.gc_divisor 100
|
|
23
|
+
|
|
24
|
+
COPY . /app/code/
|
|
25
|
+
|
|
26
|
+
RUN composer install --no-dev --optimize-autoloader
|
|
27
|
+
|
|
28
|
+
RUN chown -R www-data.www-data /app/code
|
|
29
|
+
|
|
30
|
+
CMD [ "/app/code/start.sh" ]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<VirtualHost *:3000>
|
|
2
|
+
DocumentRoot /app/code/public
|
|
3
|
+
|
|
4
|
+
ErrorLog "|/bin/cat"
|
|
5
|
+
CustomLog "|/bin/cat" combined
|
|
6
|
+
|
|
7
|
+
<Directory /app/code/public/>
|
|
8
|
+
Options +FollowSymLinks
|
|
9
|
+
AllowOverride All
|
|
10
|
+
Require all granted
|
|
11
|
+
</Directory>
|
|
12
|
+
|
|
13
|
+
<Directory /app/code/>
|
|
14
|
+
Require all denied
|
|
15
|
+
</Directory>
|
|
16
|
+
|
|
17
|
+
</VirtualHost>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
require_once __DIR__ . '/../vendor/autoload.php';
|
|
3
|
+
|
|
4
|
+
$host = getenv("CLOUDRON_MYSQL_HOST");
|
|
5
|
+
$port = getenv("CLOUDRON_MYSQL_PORT");
|
|
6
|
+
$username = getenv("CLOUDRON_MYSQL_USERNAME");
|
|
7
|
+
$password = getenv("CLOUDRON_MYSQL_PASSWORD");
|
|
8
|
+
$database = getenv("CLOUDRON_MYSQL_DATABASE");
|
|
9
|
+
|
|
10
|
+
echo "<h1>Hello from Cloudron!</h1>\n";
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
$dsn = "mysql:host=$host;port=$port;dbname=$database";
|
|
14
|
+
$pdo = new PDO($dsn, $username, $password);
|
|
15
|
+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
16
|
+
echo "<p>MySQL connection successful.</p>\n";
|
|
17
|
+
} catch (PDOException $e) {
|
|
18
|
+
echo "<p>MySQL connection failed: " . htmlspecialchars($e->getMessage()) . "</p>\n";
|
|
19
|
+
}
|
|
20
|
+
?>
|