update
This commit is contained in:
parent
f91e50fe6a
commit
21f2636c3e
20
.env-example
20
.env-example
@ -1,20 +0,0 @@
|
||||
PORT=3000
|
||||
WEB_PORT=3700
|
||||
IP=0.0.0.0
|
||||
ROOT_PATH=/root/newmail/api
|
||||
NODE_ENV=production
|
||||
DB_HOST=localhost
|
||||
DB_USER=postfix
|
||||
DB_PASS=CHANGEME
|
||||
DB_NAME=CHANGEME
|
||||
JWT_SECRET=CHANGEME
|
||||
SMTP_HOST=postfix
|
||||
SMTP_PORT=587
|
||||
SMTP_SECURE=false
|
||||
SMTP_USER=admin@localhost
|
||||
SMTP_PASS=CHANGEME
|
||||
CF_API_TOKEN=CHANGEME
|
||||
CF_EMAIL=CHANGEME
|
||||
SERVER_IP=CHANGEME
|
||||
MAILSERVER_CONTAINER=mailserver_postfix
|
||||
CONFIG_PATH=/tmp/docker-mailserver/config/
|
||||
@ -1,8 +1,5 @@
|
||||
# Roundcube Webmail
|
||||
server {
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
listen 80;
|
||||
server_name webmail.2weekmail.fyi;
|
||||
|
||||
# Security headers
|
||||
@ -13,7 +10,6 @@ server {
|
||||
|
||||
# Proxy settings
|
||||
location / {
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
proxy_pass http://localhost:8081; # Roundcube container port
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
@ -30,13 +26,17 @@ server {
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/2weekmail.fyi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/2weekmail.fyi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
|
||||
# PostfixAdmin
|
||||
server {
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
listen 80;
|
||||
server_name admin.2weekmail.fyi;
|
||||
|
||||
# Security headers
|
||||
@ -47,7 +47,6 @@ server {
|
||||
|
||||
# Proxy settings
|
||||
location / {
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
proxy_pass http://localhost:8080; # PostfixAdmin container port
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
@ -59,13 +58,17 @@ server {
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/2weekmail.fyi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/2weekmail.fyi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
|
||||
# API Service
|
||||
server {
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
listen 80;
|
||||
server_name api.2weekmail.fyi;
|
||||
|
||||
# Security headers
|
||||
@ -76,8 +79,7 @@ server {
|
||||
|
||||
# Proxy settings
|
||||
location / {
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
proxy_pass http://localhost:3000; # API container port
|
||||
proxy_pass http://localhost:3000/api/; # API container port
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@ -93,13 +95,17 @@ server {
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 300s; # Longer timeout for API calls
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/2weekmail.fyi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/2weekmail.fyi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
|
||||
# Home page
|
||||
server {
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
listen 80;
|
||||
server_name 2weekmail.fyi;
|
||||
|
||||
# Security headers
|
||||
@ -110,8 +116,7 @@ server {
|
||||
|
||||
# Proxy settings
|
||||
location / {
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
proxy_pass http://localhost:3350; # API container port
|
||||
proxy_pass http://localhost:3700; # API container port
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@ -127,4 +132,59 @@ server {
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 300s; # Longer timeout for API calls
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/2weekmail.fyi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/2weekmail.fyi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = 2weekmail.fyi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name 2weekmail.fyi;
|
||||
return 404; # managed by Certbot
|
||||
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = webmail.2weekmail.fyi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name webmail.2weekmail.fyi;
|
||||
return 404; # managed by Certbot
|
||||
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = admin.2weekmail.fyi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name admin.2weekmail.fyi;
|
||||
return 404; # managed by Certbot
|
||||
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = api.2weekmail.fyi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name api.2weekmail.fyi;
|
||||
return 404; # managed by Certbot
|
||||
|
||||
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
PORT=3000
|
||||
WEB_PORT=3700
|
||||
IP=0.0.0.0
|
||||
ROOT_PATH=/root/newmail/api
|
||||
NODE_ENV=production
|
||||
DB_HOST=localhost
|
||||
DB_USER=postfix
|
||||
DB_PASS=CHANGEME
|
||||
DB_NAME=CHANGEME
|
||||
JWT_SECRET=CHANGEME
|
||||
SMTP_HOST=postfix
|
||||
SMTP_PORT=587
|
||||
SMTP_SECURE=false
|
||||
SMTP_USER=admin@localhost
|
||||
SMTP_PASS=CHANGEME
|
||||
CF_API_TOKEN=CHANGEME
|
||||
CF_EMAIL=CHANGEME
|
||||
SERVER_IP=CHANGEME
|
||||
MAILSERVER_CONTAINER=mailserver_postfix
|
||||
CONFIG_PATH=/tmp/docker-mailserver/config/
|
||||
@ -5,6 +5,11 @@ WORKDIR /app
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
RUN apt-get update && apt-get install -y \
|
||||
opendkim \
|
||||
opendkim-tools \
|
||||
openssl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||
21
api/db/migrations/20250320064614_add_id_to_mailboxes.js
Normal file
21
api/db/migrations/20250320064614_add_id_to_mailboxes.js
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.alterTable('mailbox', function (table) {
|
||||
table.bigInteger('id');
|
||||
|
||||
table.index('id');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.alterTable('mailbox', function (table) {
|
||||
table.dropColumn('id');
|
||||
});
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.alterTable('mailbox', function (table) {
|
||||
table.uuid('id').alter();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.alterTable('mailbox', function (table) {
|
||||
table.bigInteger('id').alter();
|
||||
});
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
const BaseModel = require('./BaseModel');
|
||||
const { Model } = require('objection');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
class Mailbox extends BaseModel {
|
||||
static get tableName() {
|
||||
@ -16,6 +17,7 @@ class Mailbox extends BaseModel {
|
||||
required: ['username', 'password', 'name', 'domain', 'local_part'],
|
||||
|
||||
properties: {
|
||||
id: { type: 'string', format: 'uuid', maxLength: 36, default: uuidv4() },
|
||||
username: { type: 'string', minLength: 1, maxLength: 255 },
|
||||
password: { type: 'string', minLength: 1, maxLength: 255 },
|
||||
name: { type: 'string', maxLength: 255 },
|
||||
|
||||
@ -5,6 +5,9 @@ const execPromise = util.promisify(exec);
|
||||
require('dotenv').config();
|
||||
const path = require('path');
|
||||
const { models } = require(path.resolve(process.env.ROOT_PATH, './db/db.js'));
|
||||
const net = require('net');
|
||||
const fs = require('fs').promises;
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Create Cloudflare API client
|
||||
const createCloudflareClient = () => {
|
||||
@ -37,20 +40,21 @@ const createCloudflareClient = () => {
|
||||
|
||||
async function generateDkimKey(domain) {
|
||||
try {
|
||||
// Ensure the domain directory exists in the container
|
||||
await execPromise(`docker exec mailserver_opendkim mkdir -p /etc/opendkim/keys/${domain}`);
|
||||
// Create directory if it doesn't exist
|
||||
const keyPath = `/etc/opendkim/keys/${domain}`;
|
||||
await fs.mkdir(keyPath, { recursive: true });
|
||||
|
||||
// Generate the DKIM key
|
||||
await execPromise(`docker exec mailserver_opendkim opendkim-genkey -D /etc/opendkim/keys/${domain} -d ${domain} -s mail`);
|
||||
// Generate the DKIM key using opendkim-genkey directly
|
||||
execSync(`opendkim-genkey -D ${keyPath} -d ${domain} -s mail`);
|
||||
|
||||
// Set proper permissions
|
||||
await execPromise(`docker exec mailserver_opendkim chown -R opendkim:opendkim /etc/opendkim/keys/${domain}`);
|
||||
// Set proper permissions (if needed)
|
||||
execSync(`chown -R opendkim:opendkim ${keyPath}`);
|
||||
|
||||
// Read the generated public key
|
||||
const { stdout } = await execPromise(`docker exec mailserver_opendkim cat /etc/opendkim/keys/${domain}/mail.txt`);
|
||||
const publicKeyContent = await fs.readFile(`${keyPath}/mail.txt`, 'utf8');
|
||||
|
||||
// Extract the DKIM record value
|
||||
const dkimMatch = stdout.match(/p=([^)]+)/);
|
||||
const dkimMatch = publicKeyContent.match(/p=([^)]+)/);
|
||||
const dkimValue = dkimMatch ? dkimMatch[1] : null;
|
||||
|
||||
if (!dkimValue) {
|
||||
@ -181,14 +185,26 @@ async function configureDNS(domain) {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkOpenDkimAvailability() {
|
||||
try {
|
||||
await execPromise('docker exec mailserver_opendkim echo "OpenDKIM is available"');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('OpenDKIM container is not available:', error.message);
|
||||
return false;
|
||||
}
|
||||
function checkOpenDKIM() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new net.Socket();
|
||||
|
||||
client.connect(8891, 'opendkim', () => {
|
||||
client.destroy();
|
||||
resolve(true);
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
client.destroy();
|
||||
reject(err);
|
||||
});
|
||||
|
||||
// Add timeout
|
||||
setTimeout(() => {
|
||||
client.destroy();
|
||||
reject(new Error('Connection timeout'));
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
async function configure2WeekMailDNS() {
|
||||
@ -328,7 +344,7 @@ async function configure2WeekMailDNS() {
|
||||
async function exportAllDomains() {
|
||||
try {
|
||||
// Check if OpenDKIM is available
|
||||
const isOpenDkimAvailable = await checkOpenDkimAvailability();
|
||||
const isOpenDkimAvailable = await checkOpenDKIM();
|
||||
if (!isOpenDkimAvailable) {
|
||||
console.error('Cannot proceed: OpenDKIM container is not available');
|
||||
return;
|
||||
@ -354,7 +370,7 @@ async function exportAllDomains() {
|
||||
|
||||
if (success) {
|
||||
// Update the domain record to mark it as configured in Cloudflare
|
||||
await models.Domain.query().findById(domain.id).patch({ in_cloudflare: 1 });
|
||||
await models.Domain.query().where('domain', domain.domain).patch({ in_cloudflare: 1 });
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
|
||||
@ -7,8 +7,8 @@ require("dotenv").config();
|
||||
|
||||
async function main() {
|
||||
const password = crypto.randomBytes(32).toString("hex");
|
||||
const email = "admin@2weekmail.fyi";
|
||||
const username = "admin";
|
||||
const email = process.argv[2];
|
||||
const username = process.argv[3];
|
||||
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const passwordEncrypted = await bcrypt.hash(password, salt);
|
||||
|
||||
3
api/test.js
Normal file
3
api/test.js
Normal file
@ -0,0 +1,3 @@
|
||||
const uuid = require('uuid');
|
||||
|
||||
console.log(uuid.v4());
|
||||
@ -154,6 +154,7 @@ services:
|
||||
volumes:
|
||||
- ./api:/app
|
||||
- /app/node_modules
|
||||
- opendkim_data:/etc/opendkim
|
||||
environment:
|
||||
- PORT=${PORT}
|
||||
- WEB_PORT=${WEB_PORT}
|
||||
@ -165,7 +166,7 @@ services:
|
||||
- DB_PASS=${DB_PASS}
|
||||
- DB_NAME=${DB_NAME}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- SMTP_HOST=${SMTP_HOST}
|
||||
- SMTP_HOST=mailserver
|
||||
- SMTP_PORT=${SMTP_PORT}
|
||||
- SMTP_SECURE=${SMTP_SECURE}
|
||||
- SMTP_USER=${SMTP_USER}
|
||||
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "2weekmail",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user