setup.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { installPlugins } from "./lib/certbot.js";
  2. import utils from "./lib/utils.js";
  3. import { setup as logger } from "./logger.js";
  4. import authModel from "./models/auth.js";
  5. import certificateModel from "./models/certificate.js";
  6. import settingModel from "./models/setting.js";
  7. import userModel from "./models/user.js";
  8. import userPermissionModel from "./models/user_permission.js";
  9. export const isSetup = async () => {
  10. const row = await userModel.query().select("id").where("is_deleted", 0).first();
  11. return row?.id > 0;
  12. }
  13. /**
  14. * Creates a default admin users if one doesn't already exist in the database
  15. *
  16. * @returns {Promise}
  17. */
  18. const setupDefaultUser = async () => {
  19. const initialAdminEmail = process.env.INITIAL_ADMIN_EMAIL;
  20. const initialAdminPassword = process.env.INITIAL_ADMIN_PASSWORD;
  21. // This will only create a new user when there are no active users in the database
  22. // and the INITIAL_ADMIN_EMAIL and INITIAL_ADMIN_PASSWORD environment variables are set.
  23. // Otherwise, users should be shown the setup wizard in the frontend.
  24. // I'm keeping this legacy behavior in case some people are automating deployments.
  25. if (!initialAdminEmail || !initialAdminPassword) {
  26. return Promise.resolve();
  27. }
  28. const userIsetup = await isSetup();
  29. if (!userIsetup) {
  30. // Create a new user and set password
  31. logger.info(`Creating a new user: ${initialAdminEmail} with password: ${initialAdminPassword}`);
  32. const data = {
  33. is_deleted: 0,
  34. email: email,
  35. name: "Administrator",
  36. nickname: "Admin",
  37. avatar: "",
  38. roles: ["admin"],
  39. };
  40. const user = await userModel
  41. .query()
  42. .insertAndFetch(data);
  43. await authModel
  44. .query()
  45. .insert({
  46. user_id: user.id,
  47. type: "password",
  48. secret: password,
  49. meta: {},
  50. });
  51. await userPermissionModel.query().insert({
  52. user_id: user.id,
  53. visibility: "all",
  54. proxy_hosts: "manage",
  55. redirection_hosts: "manage",
  56. dead_hosts: "manage",
  57. streams: "manage",
  58. access_lists: "manage",
  59. certificates: "manage",
  60. });
  61. logger.info("Initial admin setup completed");
  62. }
  63. };
  64. /**
  65. * Creates default settings if they don't already exist in the database
  66. *
  67. * @returns {Promise}
  68. */
  69. const setupDefaultSettings = async () => {
  70. const row = await settingModel
  71. .query()
  72. .select("id")
  73. .where({ id: "default-site" })
  74. .first();
  75. if (!row?.id) {
  76. await settingModel
  77. .query()
  78. .insert({
  79. id: "default-site",
  80. name: "Default Site",
  81. description: "What to show when Nginx is hit with an unknown Host",
  82. value: "congratulations",
  83. meta: {},
  84. });
  85. logger.info("Default settings added");
  86. }
  87. };
  88. /**
  89. * Installs all Certbot plugins which are required for an installed certificate
  90. *
  91. * @returns {Promise}
  92. */
  93. const setupCertbotPlugins = async () => {
  94. const certificates = await certificateModel
  95. .query()
  96. .where("is_deleted", 0)
  97. .andWhere("provider", "letsencrypt");
  98. if (certificates?.length) {
  99. const plugins = [];
  100. const promises = [];
  101. certificates.map((certificate) => {
  102. if (certificate.meta && certificate.meta.dns_challenge === true) {
  103. if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
  104. plugins.push(certificate.meta.dns_provider);
  105. }
  106. // Make sure credentials file exists
  107. const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
  108. // Escape single quotes and backslashes
  109. if (typeof certificate.meta.dns_provider_credentials === "string") {
  110. const escapedCredentials = certificate.meta.dns_provider_credentials
  111. .replaceAll("'", "\\'")
  112. .replaceAll("\\", "\\\\");
  113. const credentials_cmd = `[ -f '${credentials_loc}' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo '${escapedCredentials}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'; }`;
  114. promises.push(utils.exec(credentials_cmd));
  115. }
  116. }
  117. return true;
  118. });
  119. await installPlugins(plugins);
  120. if (promises.length) {
  121. await Promise.all(promises);
  122. logger.info(`Added Certbot plugins ${plugins.join(", ")}`);
  123. }
  124. }
  125. };
  126. /**
  127. * Starts a timer to call run the logrotation binary every two days
  128. * @returns {Promise}
  129. */
  130. const setupLogrotation = () => {
  131. const intervalTimeout = 1000 * 60 * 60 * 24 * 2; // 2 days
  132. const runLogrotate = async () => {
  133. try {
  134. await utils.exec("logrotate /etc/logrotate.d/nginx-proxy-manager");
  135. logger.info("Logrotate completed.");
  136. } catch (e) {
  137. logger.warn(e);
  138. }
  139. };
  140. logger.info("Logrotate Timer initialized");
  141. setInterval(runLogrotate, intervalTimeout);
  142. // And do this now as well
  143. return runLogrotate();
  144. };
  145. export default () => setupDefaultUser().then(setupDefaultSettings).then(setupCertbotPlugins).then(setupLogrotation);