Compare commits

...

3 Commits

Author SHA1 Message Date
Owen 7506c69c3c Rename newt site to site 2026-09-08 17:30:22 -04:00
Owen eb133f6254 Update the install and run commands to use the cli 2026-09-08 17:23:49 -04:00
Owen 251f2dd1de Replace newt and olm with pangolin-cli 2026-09-08 16:47:31 -04:00
4 changed files with 189 additions and 73 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ export const clearExitNodes: CommandModule<
// Delete all exit nodes // Delete all exit nodes
const deletedCount = await db const deletedCount = await db
.delete(exitNodes) .delete(exitNodes)
.where(eq(exitNodes.exitNodeId, exitNodes.exitNodeId)) .returning();; // delete all .where(eq(exitNodes.exitNodeId, exitNodes.exitNodeId)).returning();; // delete all
console.log(`Deleted ${deletedCount.length} exit node(s) from the database`); console.log(`Deleted ${deletedCount.length} exit node(s) from the database`);
+5 -3
View File
@@ -152,7 +152,7 @@
"siteResourcesHowToAccess": "How to access", "siteResourcesHowToAccess": "How to access",
"siteResourcesTargetsOnSite": "Targets on this site", "siteResourcesTargetsOnSite": "Targets on this site",
"siteSetting": "{siteName} Settings", "siteSetting": "{siteName} Settings",
"siteNewtTunnel": "Newt Site (Recommended)", "siteNewtTunnel": "Pangolin Site (Recommended)",
"siteNewtTunnelDescription": "Easiest way to create an entrypoint into any network. No extra setup.", "siteNewtTunnelDescription": "Easiest way to create an entrypoint into any network. No extra setup.",
"siteWg": "Basic WireGuard", "siteWg": "Basic WireGuard",
"siteWgDescription": "Use any WireGuard client to establish a tunnel. Manual NAT setup required.", "siteWgDescription": "Use any WireGuard client to establish a tunnel. Manual NAT setup required.",
@@ -2898,7 +2898,7 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.", "editInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.",
"createInternalResourceDialogNoSitesAvailable": "No Sites Available", "createInternalResourceDialogNoSitesAvailable": "No Sites Available",
"createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Close", "createInternalResourceDialogClose": "Close",
"createInternalResourceDialogCreateClientResource": "Create Private Resource", "createInternalResourceDialogCreateClientResource": "Create Private Resource",
"createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization", "createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization",
@@ -3767,6 +3767,7 @@
"noData": "No Data", "noData": "No Data",
"machineClients": "Machine Clients", "machineClients": "Machine Clients",
"install": "Install", "install": "Install",
"downloadInstaller": "Download Installer",
"run": "Run", "run": "Run",
"envFile": "Environment File", "envFile": "Environment File",
"serviceFile": "Service File", "serviceFile": "Service File",
@@ -4363,5 +4364,6 @@
"rdpUnicodeKeyboardMode": "Unicode keyboard mode", "rdpUnicodeKeyboardMode": "Unicode keyboard mode",
"sessionToolbarShow": "Show toolbar", "sessionToolbarShow": "Show toolbar",
"sessionToolbarHide": "Hide toolbar", "sessionToolbarHide": "Hide toolbar",
"actionUpdateSiteApprovals": "Update Site Approvals" "actionUpdateSiteApprovals": "Update Site Approvals",
"check": "Check"
} }
+112 -47
View File
@@ -8,6 +8,7 @@ import {
SettingsSectionTitle SettingsSectionTitle
} from "./Settings"; } from "./Settings";
import { CheckboxWithLabel } from "./ui/checkbox"; import { CheckboxWithLabel } from "./ui/checkbox";
import { Button } from "./ui/button";
import { OptionSelect, type OptionSelectOption } from "./OptionSelect"; import { OptionSelect, type OptionSelectOption } from "./OptionSelect";
import { useState } from "react"; import { useState } from "react";
import { import {
@@ -18,11 +19,14 @@ import {
FaLinux, FaLinux,
FaWindows FaWindows
} from "react-icons/fa"; } from "react-icons/fa";
import { ExternalLink } from "lucide-react"; import { Download, ExternalLink } from "lucide-react";
import { SiKubernetes, SiNixos } from "react-icons/si"; import { SiKubernetes, SiNixos } from "react-icons/si";
import { useEnvContext } from "@app/hooks/useEnvContext"; import { useEnvContext } from "@app/hooks/useEnvContext";
export type CommandItem = string | { title: string; command: string }; export type CommandItem =
| string
| { title: string; command: string }
| { title: string; link: string };
const PLATFORMS = [ const PLATFORMS = [
"linux", "linux",
@@ -41,14 +45,12 @@ export type NewtSiteInstallCommandsProps = {
id: string; id: string;
secret: string; secret: string;
endpoint: string; endpoint: string;
version?: string;
}; };
export function NewtSiteInstallCommands({ export function NewtSiteInstallCommands({
id, id,
secret, secret,
endpoint, endpoint
version = "latest"
}: NewtSiteInstallCommandsProps) { }: NewtSiteInstallCommandsProps) {
const t = useTranslations(); const t = useTranslations();
const { env } = useEnvContext(); const { env } = useEnvContext();
@@ -88,25 +90,39 @@ export function NewtSiteInstallCommands({
Run: [ Run: [
{ {
title: t("install"), title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
}, },
{ {
title: t("run"), title: t("run"),
command: `${runAsRootPrefix}newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}` command: `${runAsRootPrefix}pangolin up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
} }
], ],
"Systemd Service": [ "Auto Systemd Service": [
{ {
title: t("install"), title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
},
{
title: t("run"),
command: `sudo pangolin service install site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
},
{
title: t("check"),
command: `sudo pangolin service status site`
}
],
"Manual Systemd Service": [
{
title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
}, },
{ {
title: t("envFile"), title: t("envFile"),
command: `# Create the directory and environment file command: `# Create the directory and environment file
sudo install -d -m 0755 /etc/newt sudo install -d -m 0755 /etc/pangolin
sudo tee /etc/newt/newt.env > /dev/null << 'EOF' sudo tee /etc/pangolin/pangolin-site.env > /dev/null << 'EOF'
NEWT_ID=${id} SITE_ID=${id}
NEWT_SECRET=${secret} SITE_SECRET=${secret}
PANGOLIN_ENDPOINT=${endpoint}${ PANGOLIN_ENDPOINT=${endpoint}${
!acceptClients !acceptClients
? ` ? `
@@ -119,11 +135,11 @@ DISABLE_SSH=true`
: "" : ""
} }
EOF EOF
sudo chmod 600 /etc/newt/newt.env` sudo chmod 600 /etc/pangolin/pangolin-site.env`
}, },
{ {
title: t("serviceFile"), title: t("serviceFile"),
command: `sudo tee /etc/systemd/system/newt.service > /dev/null << 'EOF' command: `sudo tee /etc/systemd/system/pangolin-site.service > /dev/null << 'EOF'
[Unit] [Unit]
Description=Newt Description=Newt
Wants=network-online.target Wants=network-online.target
@@ -133,8 +149,8 @@ After=network-online.target
Type=simple Type=simple
User=root User=root
Group=root Group=root
EnvironmentFile=/etc/newt/newt.env EnvironmentFile=/etc/pangolin/pangolin-site.env
ExecStart=/usr/local/bin/newt ExecStart=/home/owen/fossorial/cli/bin/pangolin up site
Restart=always Restart=always
RestartSec=2 RestartSec=2
UMask=0077 UMask=0077
@@ -148,7 +164,7 @@ EOF`
{ {
title: t("enableAndStart"), title: t("enableAndStart"),
command: `sudo systemctl daemon-reload command: `sudo systemctl daemon-reload
sudo systemctl enable --now newt` sudo systemctl enable --now pangolin-site`
} }
] ]
}, },
@@ -156,23 +172,51 @@ sudo systemctl enable --now newt`
Run: [ Run: [
{ {
title: t("install"), title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
}, },
{ {
title: t("run"), title: t("run"),
command: `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` command: `pangolin up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
}
],
Service: [
{
title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
},
{
title: t("run"),
command: `sudo pangolin service install site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
},
{
title: t("check"),
command: `sudo pangolin service status site`
} }
] ]
}, },
windows: { windows: {
x64: [ Run: [
{ {
title: t("install"), title: t("install"),
command: `curl -o newt.exe -L "https://github.com/fosrl/newt/releases/download/${version}/newt_windows_amd64.exe"` link: `https://github.com/fosrl/cli/releases/latest/download/pangolin-cli_windows_installer.msi`
}, },
{ {
title: t("run"), title: t("run"),
command: `newt.exe --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` command: `pangolin up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
}
],
Service: [
{
title: t("install"),
link: `https://github.com/fosrl/cli/releases/latest/download/pangolin-cli_windows_installer.msi`
},
{
title: t("run"),
command: `pangolin service install site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
},
{
title: t("check"),
command: `pangolin service status site`
} }
] ]
}, },
@@ -180,19 +224,20 @@ sudo systemctl enable --now newt`
"Docker Compose": [ "Docker Compose": [
`services: `services:
newt: newt:
image: fosrl/newt image: fosrl/pangolin-cli
container_name: newt container_name: newt
restart: unless-stopped restart: unless-stopped
environment: environment:
- PANGOLIN_ENDPOINT=${endpoint} - PANGOLIN_ENDPOINT=${endpoint}
- NEWT_ID=${id} - SITE_ID=${id}
- NEWT_SECRET=${secret}${acceptClientsEnv}` - SITE_SECRET=${secret}${acceptClientsEnv}`
], ],
"Docker Run": [ "Docker Run": [
`docker run -dit --network host fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` `docker run -dit --network host fosrl/pangolin-cli up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
] ]
}, },
kubernetes: { kubernetes: {
// we are leaving this using newt until we change it to use the cli
"Helm Chart": [ "Helm Chart": [
`helm repo add fossorial https://charts.fossorial.io`, `helm repo add fossorial https://charts.fossorial.io`,
`helm repo update fossorial`, `helm repo update fossorial`,
@@ -216,15 +261,15 @@ sudo systemctl enable --now newt`
podman: { podman: {
"Podman Quadlet": [ "Podman Quadlet": [
`[Unit] `[Unit]
Description=Newt container Description=Pangolin Site Container
[Container] [Container]
ContainerName=newt ContainerName=pangolin-site
Image=docker.io/fosrl/newt Image=docker.io/fosrl/pangolin-cli
Environment=PANGOLIN_ENDPOINT=${endpoint} Environment=PANGOLIN_ENDPOINT=${endpoint}
Environment=NEWT_ID=${id} Environment=SITE_ID=${id}
Environment=NEWT_SECRET=${secret}${!acceptClients ? "\nEnvironment=DISABLE_CLIENTS=true" : ""} Environment=SITE_SECRET=${secret}${!acceptClients ? "\nEnvironment=DISABLE_CLIENTS=true" : ""}
# Secret=newt-secret,type=env,target=NEWT_SECRET # Secret=pangolin-secret,type=env,target=SITE_SECRET
[Service] [Service]
Restart=always Restart=always
@@ -233,12 +278,12 @@ Restart=always
WantedBy=default.target` WantedBy=default.target`
], ],
"Podman Run": [ "Podman Run": [
`podman run -dit docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` `podman run -dit docker.io/fosrl/pangolin-cli up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
] ]
}, },
nixos: { nixos: {
Flake: [ Flake: [
`${runAsRootPrefix}nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}` `${runAsRootPrefix}nix run 'nixpkgs#pangolin-cli' -- up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
] ]
} }
}; };
@@ -277,9 +322,7 @@ WantedBy=default.target`
/> />
<OptionSelect<string> <OptionSelect<string>
label={ label={t("method")}
platform === "windows" ? t("architecture") : t("method")
}
options={getArchitectures(platform).map((arch) => ({ options={getArchitectures(platform).map((arch) => ({
value: arch, value: arch,
label: arch label: arch
@@ -377,14 +420,23 @@ WantedBy=default.target`
)} )}
<div className="mt-2 space-y-3"> <div className="mt-2 space-y-3">
{commands.map((item, index) => { {commands.map((item, index) => {
const isLink =
typeof item !== "string" && "link" in item;
const commandText = const commandText =
typeof item === "string" ? item : item.command; typeof item === "string"
? item
: isLink
? undefined
: item.command;
const linkHref = isLink
? (item as { link: string }).link
: undefined;
const title = const title =
typeof item === "string" typeof item === "string"
? undefined ? undefined
: item.title; : item.title;
const key = `${title ?? ""}::${commandText}`; const key = `${title ?? ""}::${commandText ?? linkHref}`;
return ( return (
<div key={key}> <div key={key}>
@@ -393,10 +445,23 @@ WantedBy=default.target`
{title} {title}
</p> </p>
)} )}
<CopyTextBox {isLink ? (
text={commandText} <Button
outline={true} asChild
/> variant="outline"
className="w-full"
>
<a href={linkHref}>
<Download className="h-4 w-4 mr-2" />
{t("downloadInstaller")}
</a>
</Button>
) : (
<CopyTextBox
text={commandText!}
outline={true}
/>
)}
</div> </div>
); );
})} })}
@@ -456,11 +521,11 @@ function getPlatformName(platformName: Platform) {
function getArchitectures(platform: Platform) { function getArchitectures(platform: Platform) {
switch (platform) { switch (platform) {
case "linux": case "linux":
return ["Run", "Systemd Service"]; return ["Run", "Auto Systemd Service", "Manual Systemd Service"];
case "macos": case "macos":
return ["Run"]; return ["Run", "Service"];
case "windows": case "windows":
return ["x64"]; return ["Run", "Service"];
case "docker": case "docker":
return ["Docker Compose", "Docker Run"]; return ["Docker Compose", "Docker Run"];
case "kubernetes": case "kubernetes":
+71 -22
View File
@@ -1,4 +1,4 @@
import { Terminal } from "lucide-react"; import { Download, Terminal } from "lucide-react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useState } from "react"; import { useState } from "react";
import { FaDocker, FaWindows } from "react-icons/fa"; import { FaDocker, FaWindows } from "react-icons/fa";
@@ -10,9 +10,13 @@ import {
SettingsSectionHeader, SettingsSectionHeader,
SettingsSectionTitle SettingsSectionTitle
} from "./Settings"; } from "./Settings";
import { Button } from "./ui/button";
import { OptionSelect, type OptionSelectOption } from "./OptionSelect"; import { OptionSelect, type OptionSelectOption } from "./OptionSelect";
export type CommandItem = string | { title: string; command: string }; export type CommandItem =
| string
| { title: string; command: string }
| { title: string; link: string };
const PLATFORMS = ["unix", "docker", "windows"] as const; const PLATFORMS = ["unix", "docker", "windows"] as const;
@@ -22,14 +26,12 @@ export type OlmInstallCommandsProps = {
id: string; id: string;
secret: string; secret: string;
endpoint: string; endpoint: string;
version?: string;
}; };
export function OlmInstallCommands({ export function OlmInstallCommands({
id, id,
secret, secret,
endpoint, endpoint
version = "latest"
}: OlmInstallCommandsProps) { }: OlmInstallCommandsProps) {
const t = useTranslations(); const t = useTranslations();
@@ -40,14 +42,28 @@ export function OlmInstallCommands({
const commandList: Record<Platform, Record<string, CommandItem[]>> = { const commandList: Record<Platform, Record<string, CommandItem[]>> = {
unix: { unix: {
All: [ Run: [
{ {
title: t("install"), title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-cli.sh | sudo bash` command: `curl -fsSL https://static.pangolin.net/get-cli.sh | sudo bash`
}, },
{ {
title: t("run"), title: t("run"),
command: `sudo pangolin up --id ${id} --secret ${secret} --endpoint ${endpoint} --attach` command: `sudo pangolin up client --id ${id} --secret ${secret} --endpoint ${endpoint} --attach`
}
],
Service: [
{
title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
},
{
title: t("run"),
command: `sudo pangolin service install client --id ${id} --secret ${secret} --endpoint ${endpoint}`
},
{
title: t("check"),
command: `sudo pangolin service status client`
} }
] ]
}, },
@@ -73,15 +89,28 @@ export function OlmInstallCommands({
] ]
}, },
windows: { windows: {
x64: [ Run: [
{ {
title: t("install"), title: t("install"),
command: `# Download and run the installer to install Olm first\n link: `https://github.com/fosrl/cli/releases/latest/download/pangolin-cli_windows_installer.msi`
curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/olm_windows_installer.exe"`
}, },
{ {
title: t("run"), title: t("run"),
command: `olm.exe --id ${id} --secret ${secret} --endpoint ${endpoint}` command: `pangolin up client --id ${id} --secret ${secret} --endpoint ${endpoint}`
}
],
Service: [
{
title: t("install"),
link: `https://github.com/fosrl/cli/releases/latest/download/pangolin-cli_windows_installer.msi`
},
{
title: t("run"),
command: `pangolin service install client --id ${id} --secret ${secret} --endpoint ${endpoint}`
},
{
title: t("check"),
command: `pangolin service status client`
} }
] ]
} }
@@ -121,9 +150,7 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
/> />
<OptionSelect<string> <OptionSelect<string>
label={ label={t("method")}
platform === "docker" ? t("method") : t("architecture")
}
options={getArchitectures(platform).map((arch) => ({ options={getArchitectures(platform).map((arch) => ({
value: arch, value: arch,
label: arch label: arch
@@ -138,8 +165,17 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
<p className="font-semibold mb-3">{t("commands")}</p> <p className="font-semibold mb-3">{t("commands")}</p>
<div className="mt-2 space-y-3"> <div className="mt-2 space-y-3">
{commands.map((item, index) => { {commands.map((item, index) => {
const isLink =
typeof item !== "string" && "link" in item;
const commandText = const commandText =
typeof item === "string" ? item : item.command; typeof item === "string"
? item
: isLink
? undefined
: item.command;
const linkHref = isLink
? (item as { link: string }).link
: undefined;
const title = const title =
typeof item === "string" typeof item === "string"
? undefined ? undefined
@@ -152,10 +188,23 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
{title} {title}
</p> </p>
)} )}
<CopyTextBox {isLink ? (
text={commandText} <Button
outline={true} asChild
/> variant="outline"
className="w-full"
>
<a href={linkHref}>
<Download className="h-4 w-4 mr-2" />
{t("downloadInstaller")}
</a>
</Button>
) : (
<CopyTextBox
text={commandText!}
outline={true}
/>
)}
</div> </div>
); );
})} })}
@@ -169,13 +218,13 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
function getArchitectures(platform: Platform) { function getArchitectures(platform: Platform) {
switch (platform) { switch (platform) {
case "unix": case "unix":
return ["All"]; return ["Run", "Service"];
case "windows": case "windows":
return ["x64"]; return ["Run", "Service"];
case "docker": case "docker":
return ["Docker Compose", "Docker Run"]; return ["Docker Compose", "Docker Run"];
default: default:
return ["x64"]; return ["Run"];
} }
} }