import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import Image from "next/image" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" import { DataFlowDiagram } from "@/components/ui/data-flow-diagram" import CopyableCode from "@/components/CopyableCode" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.storageShare.lxcSambaServer.meta" }) return { title: t("title"), description: t("description"), openGraph: { title: t("ogTitle"), description: t("ogDescription"), type: "article", url: "https://macrimi.github.io/ProxMenux/docs/storage-share/lxc-samba-server", }, } } type StringItem = string type RelatedItem = { href: string; label: string; tail?: string; tailRich?: string } export default async function LxcSambaServerPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.storageShare.lxcSambaServer" }) const messages = (await getMessages({ locale })) as unknown as { docs: { storageShare: { lxcSambaServer: { troubleshoot: { aptItems: StringItem[] } related: { items: RelatedItem[] } } } } } const aptItems = messages.docs.storageShare.lxcSambaServer.troubleshoot.aptItems const relatedItems = messages.docs.storageShare.lxcSambaServer.related.items const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} const nfsLink = (chunks: React.ReactNode) => ( {chunks} ) const clientLink = (chunks: React.ReactNode) => ( {chunks} ) return (
{t.rich("privReq.body", { code, strong })}

{t("what.heading")}

{t.rich("what.body", { code })}

] path = /mnt/data valid users = force group = sharedfiles read only = no create mask = 0664 directory mask = 2775`} />

{t("perms.heading")}

{t.rich("perms.body", { code, strong })}

{t("perms.headerType")} {t("perms.headerAction")}
{t("perms.bindType")}
{t.rich("perms.bindTypeSubRich", { code })}
{t.rich("perms.bindActionRich", { code })}
{t("perms.localType")}
{t("perms.localTypeSub")}
{t.rich("perms.localActionRich", { code })}
{t.rich("perms.gidBody", { strong, code, nfsLink })}

{t("opening.heading")}

{t.rich("opening.body", { strong })}

{t("opening.imageAlt")}

{t("howRuns.heading")}

{`┌─────────────────────────────────────────────┐
│  PHASE 1 — Pick CT, folder, user, options   │
│  (nothing touched yet)                      │
└──────────────────┬──────────────────────────┘
                   ▼
      Privileged-CT gate (share-common.func)
      ├─ pct list — pick CT
      ├─ Auto-start if stopped
      └─ Aborts if "unprivileged: 1" in CT config
                   │
                   ▼
      Folder selection (2 modes)
      ├─ Auto: choose from /mnt/* in the CT
      └─ Manual: enter any absolute path
         (offers to mkdir -p if missing)
                   │
                   ▼
      Samba install check
      ├─ Already installed?
      │    └─ Detect existing user via pdbedit -L
      └─ First time?
         ├─ apt-get install samba samba-common-bin acl
         ├─ Ask username (default: "proxmenux")
         ├─ Ask password (twice — must match)
         ├─ adduser  (no password)
         └─ smbpasswd -a 
                   │
                   ▼
      Permission setup (2 paths)
      ├─ Bind-mount detected
      │     groupadd -g 999 sharedfiles
      │     usermod -aG sharedfiles 
      │     chown root:sharedfiles + chmod 2775
      │     setfacl fallback if write fails
      └─ Local folder
            chown -R :
            chmod -R 755
            setfacl fallback if needed
                   │
                   ▼
      Share permissions (3 modes)
      ├─ rw — read-write block (default)
      ├─ ro — read-only block
      └─ custom — your own directives
                   │
   ┌──────── Cancel   OR   Confirm ────┐
   ▼                                   ▼
Exit, nothing        ┌─────────────────┴─────────────────┐
was changed          │  PHASE 2 — Write smb.conf + apply  │
                     └─────────────────┬─────────────────┘
                                       ▼
                       If [share-name] already in smb.conf:
                       └─ ask "update?", remove + replace
                          (sed deletes from [name] to next blank)
                       Else:
                       └─ append the new block
                                       ▼
                       systemctl restart smbd.service
                                       ▼
                       Print connection details:
                       • Server IP (hostname -I)
                       • Share name + path
                       • Username
                       • Sample mount commands`}
      

{t("modes.heading")}

{t.rich("modes.intro", { code })}

{t("modes.headerMode")} {t.rich("modes.headerBlock", { code })}
{t("modes.rwMode")}
{`read only = no
writable = yes
browseable = yes
guest ok = no
create mask = 0664
directory mask = 2775
force create mode = 0664
force directory mode = 2775`}
{t("modes.roMode")}
{`read only = yes
writable = no
browseable = yes
guest ok = no`}
{t("modes.customMode")} {t.rich("modes.customBodyRich", { code })}

{t("manual.heading")}

{t.rich("manual.body", { strong, code })}

/dev/null || true usermod -aG sharedfiles proxmenux chown root:sharedfiles /mnt/data chmod 2775 /mnt/data # fallback if user can't write: # setfacl -R -m u:proxmenux:rwx /mnt/data # 4. write the share block cat >> /etc/samba/smb.conf <<'EOF' [data] path = /mnt/data valid users = proxmenux force group = sharedfiles read only = no writable = yes browseable = yes guest ok = no create mask = 0664 directory mask = 2775 force create mode = 0664 force directory mode = 2775 veto files = /lost+found/ EOF # 5. apply systemctl restart smbd testparm -s | grep -A6 '^\\[data\\]'`} />

{t("connect.heading")}

{t("connect.headerOs")} {t("connect.headerHow")}
{t("connect.windowsOs")} {t.rich("connect.windowsHowRich", { code, em })}
{t("connect.macosOs")} {t.rich("connect.macosHowRich", { code, em })}
{t("connect.linuxOs")} {t.rich("connect.linuxHowRich", { code, clientLink })}

{t("view.heading")}

{t.rich("view.body", { code })}

{t("delete.heading")}

{t.rich("delete.body", { code })}

{t("status.heading")}

{t.rich("status.body", { code })}

{t("uninstall.heading")}

{t.rich("uninstall.body", { code, strong })}

{t.rich("uninstall.warnBody", { em, code })}

{t("troubleshoot.heading")}

{t.rich("troubleshoot.privBody", { code })} {t("troubleshoot.aptIntro")}
    {aptItems.map((_, idx) => (
  • {t.rich(`troubleshoot.aptItems.${idx}`, { code })}
  • ))}
{t("troubleshoot.aptOutro")}
{t.rich("troubleshoot.noShareBody", { code })} {t.rich("troubleshoot.authBody", { em, code })} {t.rich("troubleshoot.groupBody", { code })} {t.rich("troubleshoot.bothBody", { code })}
groupmod -g 101000 sharedfiles
chgrp -R sharedfiles /mnt/<your-share>

{t("related.heading")}

    {relatedItems.map((item, idx) => (
  • {item.label} {item.tailRich ? t.rich(`related.items.${idx}.tailRich`, { em }) : item.tail}
  • ))}
) }