Blog

  • Setup Auth.js for NextJS 15

    Setup Auth.js for NextJS 15

    Installing Auth.js

    npm install next-auth@beta

    Setup Environment

    npx auth secret

    Configure

    // ./auth.ts
    
    import { PrismaAdapter } from "@auth/prisma-adapter";
    import NextAuth from "next-auth";
    import Credentials from "next-auth/providers/credentials";
    import prisma from "./prisma";
    import bcrypt from "bcrypt";
    
    export const { handlers, signIn, signOut, auth } = NextAuth({
      adapter: PrismaAdapter(prisma),
      secret: process.env.NEXTAUTH_SECRET,
      pages: {
        signIn: "/login",
      },
      session: {
        strategy: "jwt",
        maxAge: 30 * 24 * 60 * 60, // 30 days
      },
      providers: [
        Credentials({
          name: "credentials",
          credentials: {
            email: { label: "Email", type: "email" },
            password: { label: "Password", type: "password" },
          },
          authorize: async (credentials: Record<string, string>) => {
            try {
              const { userId, password } = credentials;
              const user = await prisma.user.findFirst({
                where: {
                  OR: [{ email: userId }, { username: userId }],
                },
              });
              if (!user) return null;
              // Check if the password is correct
              const isValidPassword = await bcrypt.compare(
                password,
                user.hashedPassword
              );
              if (!isValidPassword) return null;
              return {
                fullname: user?.fullname ?? "",
                email: user?.email ?? "",
                role: user?.role?.toLocaleLowerCase() ?? "user",
                id: user?.id ?? "",
              };
            } catch (error) {
              console.error("Error authorizing credentials:", error);
              throw new Error("Invalid credentials");
            }
          },
        }),
      ],
      callbacks: {
        async jwt({ token, user }) {
          if (user) {
            token.fullname = user.fullname;
            token.role = user.role;
          }
          return token;
        },
        async session({ session, token }) {
          if (token?.role) {
            session.user.fullname = token.fullname as string;
            session.user.role = token.role as string;
          }
          return session;
        },
      },
    });
    
    // ./app/api/auth/[...nextauth]/route.ts
    
    import { handlers } from "@/auth" // Referring to the auth.ts we just created
    export const { GET, POST } = handlers
    // ./middleware.ts
    
    export { auth as middleware } from "@/auth"

    Prisma Adapter

    npm install @prisma/client @auth/prisma-adapter
    npm install prisma --save-dev
    DATABASE_URL= "postgresql://postgres:[email protected]:5432/shopcart?schema=public"
    // prima.ts
    
    import { PrismaClient } from "@prisma/client"
     
    const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
     
    export const prisma = globalForPrisma.prisma || new PrismaClient()
     
    if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma
    // prisma/schema-postgres.prisma
    
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }
     
    generator client {
      provider = "prisma-client-js"
    }
     
    model User {
      id            String          @id @default(cuid())
      name          String?
      email         String          @unique
      emailVerified DateTime?
      image         String?
      accounts      Account[]
      sessions      Session[]
      // Optional for WebAuthn support
      Authenticator Authenticator[]
     
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
    }
     
    model Account {
      userId            String
      type              String
      provider          String
      providerAccountId String
      refresh_token     String?
      access_token      String?
      expires_at        Int?
      token_type        String?
      scope             String?
      id_token          String?
      session_state     String?
     
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
     
      user User @relation(fields: [userId], references: [id], onDelete: Cascade)
     
      @@id([provider, providerAccountId])
    }
    npx prisma db push

  • Access Ollama remotely

    Access Ollama remotely

    Edit /etc/systemd/system/ollama.service (I used nano) Add (under the service category):

    Environment=”OLLAMA_HOST=0.0.0.0″

    [Unit]
    Description=Ollama Service
    After=network-online.target
    
    [Service]
    Environment="OLLAMA_HOST=0.0.0.0"
    Broadcast message from root@jellyfinollama (Mon 2025-06-30 04:03:01 UTC):
    User=ollama
    The system will reboot at Mon 2025-06-30 04:05:01 UTC!
    Restart=always
    RestartSec=3
    Broadcast message from root@jellyfinollama (Mon 2025-06-30 04:03:01 UTC)::

    Start Ollama with the command: ollama serve

  • How can I schedule a nightly reboot?

    How can I schedule a nightly reboot?

    I’d use cron (should already be installed):

    sudo crontab -e

    The first time you might have to choose your preferred editor (like nano)

    Insert a line like

    0 4   *   *   *    /sbin/shutdown -r +5

    at the bottom. Explanation:

    m      h    dom        mon   dow       command
    minute hour dayOfMonth Month dayOfWeek commandToRun

    would announce the reboot every day at 4:00am, then reboot 5 minutes later (at 4:05am).

    Ctrl+XYEnter should get you out of crontab (if using nano)

    Note: you might have to run crontab -e as root, because shutdown needs root. crontab -e opens a file in /tmp instead of the actual crontab so that it can check your new crontab for errors. If there are no errors, then your actual crontab will be updated.

  • Nginx config for webserver

    Nginx config for webserver

    server {
        server_name *.rajubk.com;
        client_max_body_size 1G;
    
        location / {
            proxy_pass http://localhost:9000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
    
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;
    
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256';
    
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer" always;
        add_header Permissions-Policy "geolocation=(), microphone=()" always;
        add_header X-XSS-Protection "1; mode=block" always;
    }
    
    # HTTP redirect block
    server {
        listen 80;
        server_name *.rajubk.com;
        return 301 https://$host$request_uri;
    }
    cd /etc/nginx/sites-enabled/
    ln -s ../sites-available/minio
    nginx -t
    systemctl reload nginx
  • Install minio on ubuntu with docker compose

    Install minio on ubuntu with docker compose

    services:
      minio:
        image: minio/minio:RELEASE.2025-03-12T18-04-18Z-cpuv1
        container_name: minio-server
        environment:
          MINIO_ROOT_USER: minioadmin
          MINIO_ROOT_PASSWORD: minioadmin
        ports:
          - "9000:9000" # MinIO API and Console
          - "9001:9001" # MinIO Console (if using separate port for console)
        volumes:
          - minio_data:/data # Mount a named volume for persistent data
        command: server /data --console-address ":9001"
        restart: unless-stopped
    
    volumes:
      minio_data:
  • Nginx config for wordpress

    Nginx config for wordpress

    server {
        listen 80;
        server_name *.rajubk.com rajubk.com;
        client_max_body_size 512M;
    
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name *.rajubk.com rajubk.com;
        client_max_body_size 512M;
    
        root /var/www/html/wordpress;
        index index.php;
    
        # SSL parameters
        ssl_certificate /etc/letsencrypt/live/rajubk.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/rajubk.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/rajubk.com/chain.pem;
    
        # Log files
        access_log /var/log/nginx/sample.com.access.log;
        error_log /var/log/nginx/sample.com.error.log;
    
        location = /favicon.ico {
            log_not_found off;
            access_log off;
        }
    
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
    
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
    
        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php8.3-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires max;
            log_not_found off;
        }
    
        # START Nginx Rewrites for Rank Math Sitemaps
        rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last;
        rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
        # END Nginx Rewrites for Rank Math Sitemaps
    }
  • NextJS send mail using nodemailer using SMTP

    NextJS send mail using nodemailer using SMTP

    import { sendMailAction } from "@/actions/action";
    
    const Page = () => {
      return (
        <form action={sendMailAction}>
          <button type="submit">Send Mail</button>
        </form>
      );
    };
    
    export default Page;
    
    "use server";
    
    import { sendMail } from "@/lib/node-mailer";
    
    export const sendMailAction = async () => {
      console.log("acgtion");
      try {
        await sendMail("[email protected]", "Test Subject", "This is a test");
      } catch (error) {
        console.log(error);
      }
    };
    import nodemailer from "nodemailer";
    
    export const sendMail = async (
      email: string,
      subject: string,
      text: string
    ) => {
      const transporter = nodemailer.createTransport({
        host: "your.smtp.server",
        port: 587,
        secure: false,
        auth: {
          user: "[email protected]",
          pass: "your_email_password",
        },
        tls: {
          rejectUnauthorized: false,
        },
      });
      try {
        await transporter.sendMail({
          from: "[email protected]",
          to: email,
          subject: subject,
          text: text,
        });
      } catch (error) {
        console.log(error);
      }
    };
    
  • WP Mail SMTP

    WP Mail SMTP

    add_filter( 'wp_mail_smtp_custom_options', function( $phpmailer ) {
        $phpmailer->SMTPOptions = array(
            'ssl' => array(
                'verify_peer' => false,
                'verify_peer_name' => false,
                'allow_self_signed' => true
            )
        );
        return $phpmailer;
    } );

  • Mail Server

    Mail Server

    ---------------------------> START DNS Records
    
    A Record to Server IP for mail.domain.tld
    CNAME autodiscover for mail.domain.tld
    CNAME autoconfig for mail.domain.tld
    MX Record for Domain.tld with Content mail.domain.tld
    SRV Record _autodiscover._tcp with Content 0 5 Port 443 Target mail.domain.tld
    TXT Record for Domain.tld with Content "v=spf1 ip4:YOUR_IPV4 ip6:YOUR_IPV6 -all"
    TXT Record for _DMARC with Content "v=DMARC1; p=quarantine; adkim=s; aspf=s"
    
    ---------------------------> END DNS Records
    ---------------------------> START Docker Installation
    
    apt update && apt upgrade -y
    dpkg-reconfigure tzdata
    
    sudo apt-get install ca-certificates curl 
    
    sudo install -m 0755 -d /etc/apt/keyrings 
    
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc 
    
    sudo chmod a+r /etc/apt/keyrings/docker.asc 
    
    echo \ 
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ 
     $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \ 
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 
    
    sudo apt-get update 
    
    apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 
    
    systemctl start docker 
    
    systemctl enable docker 
    
    docker run hello-world
    
    ---------------------------> END Docker Installation
    ---------------------------> START Mailcow Installation
    
    mkdir /docker
    mkdir /docker/mailcow && cd /docker/mailcow
    
    git clone https://github.com/mailcow/mailcow-dockerized
    
    cd mailcow-dockerized
    
    ./generate_config.sh
    
    Vim mailcow.conf
    
    # SMTP
    sudo ufw allow 25/tcp
    
    # Submission
    sudo ufw allow 587/tcp
    
    # SMTPS (deprecated but sometimes used)
    sudo ufw allow 465/tcp
    
    # IMAP (unencrypted, STARTTLS)
    sudo ufw allow 143/tcp
    
    # IMAPS (SSL/TLS)
    sudo ufw allow 993/tcp
    
    # POP3 (unencrypted, STARTTLS)
    sudo ufw allow 110/tcp
    
    # POP3S (SSL/TLS)
    sudo ufw allow 995/tcp
    
    # Sieve (for mail filtering scripts like vacation replies)
    sudo ufw allow 4190/tcp
    
    sudo ufw status
    
    Vim docker-compose.yml
    
    docker compose up -d
    
    ---------------------------> END Mailcow Installation
    ---------------------------> START NGINX Installation
    mkdir /root/.secrets/certbot/
    vim /root/.secrets/certbot/cloudflare.ini
    
    dns_cloudflare_api_token = TOKEN
    
    chmod 600 /root/.secrets/certbot/cloudflare.ini 
    
    apt install certbot python3-certbot-dns-cloudflare
    
    sudo certbot certonly \
      --dns-cloudflare \
      --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
      -d '*.domain.tld' -d domain.tld \
      --preferred-challenges dns-01 \
      --agree-tos --no-eff-email --email [email protected]
    
    apt install nginx
    
    cd /etc/nginx/sites-available
    vim mail_domain_tld
    
    cd ../sites-enabled
    ln -s ../sites-available/mail_domain_tld
    
    nginx -t
    
    systemctl reload nginx
    
    ---------------------------> END NGINX Installation
    ---------------------------> START Mailcow Login
    
    admin
    moohoo
    
    ---------------------------> START Mailcow Login
    ---------------------------> START DNS Records Part 2
    
    TLSA for _25._tcp.mail.domain.tld 3 1 1 [Value from Mailcow]
    
    TXT for dkim._domainkey.domain.tld [Value from Mailcow]
    
    ---------------------------> END DNS Records Part 2
    
    server {
        server_name domain.tld mail.domain.tld autodiscover.domain.tld autoconfig.domain.tld;
        client_max_body_size 1G;
    
        location / {
            proxy_pass http://localhost:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
    
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;
    
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256';
    
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer" always;
        add_header Permissions-Policy "geolocation=(), microphone=()" always;
        add_header X-XSS-Protection "1; mode=block" always;
    }
    
    # HTTP redirect block
    server {
        listen 80;
        server_name domain.tld mail.domain.tld autodiscover.domain.tld autoconfig.domain.tld;
        return 301 https://$host$request_uri;
    }
  • Get letsencrypt ssl certificate from cloudflare

    Get letsencrypt ssl certificate from cloudflare

    Method 1:

    sudo apt install certbot python3-certbot-dns-cloudflare -y
    
    sudo nano /etc/letsencrypt/cloudflare.conf
    
    dns_cloudflare_email="<email-id>"
    dns_cloudflare_api_key="<api-key>" # Replace with your Cloudflare API key (Not API Token)
    
    sudo chmod 600 /etc/letsencrypt/cloudflare.conf
    
    sudo certbot certonly --dns-cloudflare --manual-public-ip-logging-ok -d sample.com -d *.sample.com --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py

    Method 2:

    mkdir /root/.secrets/certbot/
    vim /root/.secrets/certbot/cloudflare.ini
    
    dns_cloudflare_api_token = TOKEN
    
    chmod 600 /root/.secrets/certbot/cloudflare.ini 
    
    apt install certbot python3-certbot-dns-cloudflare
    
    sudo certbot certonly \
      --dns-cloudflare \
      --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
      -d '*.domain.tld' -d domain.tld \
      --preferred-challenges dns-01 \
      --agree-tos --no-eff-email --email [email protected]
    
    apt install nginx
    
    cd /etc/nginx/sites-available
    vim mail_domain_tld
    
    cd ../sites-enabled
    ln -s ../sites-available/mail_domain_tld
    
    nginx -t
    
    systemctl reload nginx