mirror of
https://github.com/dalbodeule/sshchat.git
synced 2025-12-07 22:55:44 +09:00
Dockerfile and some add/fix config
This commit is contained in:
35
Dockerfile
Normal file
35
Dockerfile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Stage 1: Build the Go application
|
||||||
|
FROM golang:1.25-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy go.mod and go.sum first to leverage Docker cache
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the rest of the application source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the Go application
|
||||||
|
# CGO_ENABLED=0 disables CGO, creating a statically linked binary
|
||||||
|
# -o /app/main specifies the output path and name of the executable
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app/main .
|
||||||
|
|
||||||
|
# Stage 2: Create a minimal runtime image
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Install ca-certificates for HTTPS support if needed
|
||||||
|
RUN apk --no-cache add ca-certificates
|
||||||
|
|
||||||
|
WORKDIR /root/
|
||||||
|
|
||||||
|
# Copy the built executable from the builder stage
|
||||||
|
COPY --from=builder /app/main .
|
||||||
|
|
||||||
|
# Expose the port your application listens on (e.g., 2222)
|
||||||
|
EXPOSE 2222
|
||||||
|
ENV PORT=2222
|
||||||
|
ENV ROOT_PATH="/app/data"
|
||||||
|
|
||||||
|
# Command to run the application when the container starts
|
||||||
|
CMD ["./main"]
|
||||||
3
inc.env
3
inc.env
@@ -1,3 +1,4 @@
|
|||||||
PORT=2222
|
PORT=2222
|
||||||
GEOIP_DB=./GeoLite2-City.mmdb
|
GEOIP_DB=GeoLite2-City.mmdb
|
||||||
DB_DSN="postgrtesql://postgres:password@localhost/postgres"
|
DB_DSN="postgrtesql://postgres:password@localhost/postgres"
|
||||||
|
ROOT_PATH="./"
|
||||||
30
main.go
30
main.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -24,7 +25,12 @@ func sessionHandler(s ssh.Session, geoip *geoip2.Reader, pgDb *bun.DB) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
remote := s.RemoteAddr().String()
|
addr := s.RemoteAddr().String()
|
||||||
|
host, _, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
host = addr
|
||||||
|
}
|
||||||
|
remote := strings.Trim(host, "[]")
|
||||||
username := s.User()
|
username := s.User()
|
||||||
|
|
||||||
geoStatus := utils.GetIPInfo(remote, geoip)
|
geoStatus := utils.GetIPInfo(remote, geoip)
|
||||||
@@ -43,12 +49,14 @@ func sessionHandler(s ssh.Session, geoip *geoip2.Reader, pgDb *bun.DB) {
|
|||||||
_ = s.Close()
|
_ = s.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if geoStatus.Country == "ZZ" && !(strings.HasPrefix(remote, "127") || strings.HasPrefix(remote, "[::1]")) {
|
if geoStatus.Country == "ZZ" {
|
||||||
log.Printf("[sshchat] unknown country blacklisted. %s", username)
|
if strings.HasPrefix(remote, "127") || strings.HasPrefix(remote, "::1") {
|
||||||
_, _ = fmt.Fprintf(s, "[system] Unknown country is blacklisted. %s\n", geoStatus.Country)
|
log.Printf("[sshchat] %s is localhost whitelisted.", username)
|
||||||
_ = s.Close()
|
} else {
|
||||||
} else {
|
log.Printf("[sshchat] unknown country blacklisted. %s", username)
|
||||||
log.Printf("[sshchat] %s is localhost whitelisted.", username)
|
_, _ = fmt.Fprintf(s, "[system] Unknown country is blacklisted. %s\n", geoStatus.Country)
|
||||||
|
_ = s.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client := utils.NewClient(s, ptyReq.Window.Height, ptyReq.Window.Width, username, remote)
|
client := utils.NewClient(s, ptyReq.Window.Height, ptyReq.Window.Width, username, remote)
|
||||||
@@ -62,7 +70,7 @@ func sessionHandler(s ssh.Session, geoip *geoip2.Reader, pgDb *bun.DB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
geoip, err := utils.GetDB(config.Geoip)
|
geoip, err := utils.GetDB(config.RootPath + "/" + config.Geoip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Geoip db is error: %v", err)
|
log.Fatalf("Geoip db is error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -74,15 +82,15 @@ func main() {
|
|||||||
|
|
||||||
port := config.Port
|
port := config.Port
|
||||||
|
|
||||||
keys, err := utils.CheckHostKey()
|
keys, err := utils.CheckHostKey(config.RootPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("Failed to check SSH keys: generate one.\n", err)
|
log.Print("Failed to check SSH keys: generate one.\n", err)
|
||||||
err = utils.GenerateHostKey()
|
err = utils.GenerateHostKey(config.RootPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
keys, err = utils.CheckHostKey()
|
keys, err = utils.CheckHostKey(config.RootPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -13,23 +12,23 @@ type Config struct {
|
|||||||
Geoip string
|
Geoip string
|
||||||
CountryBlacklist []string
|
CountryBlacklist []string
|
||||||
PgDsn string
|
PgDsn string
|
||||||
|
RootPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfig() *Config {
|
func GetConfig() *Config {
|
||||||
err := godotenv.Load()
|
_ = godotenv.Load()
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error loading .env file")
|
|
||||||
}
|
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
geoipDbfile := os.Getenv("GEOIP_DB")
|
geoipDbfile := os.Getenv("GEOIP_DB")
|
||||||
countryBlacklist := os.Getenv("COUNTRY_BLACKLIST")
|
countryBlacklist := os.Getenv("COUNTRY_BLACKLIST")
|
||||||
pgDsn := os.Getenv("DB_DSN")
|
pgDsn := os.Getenv("DB_DSN")
|
||||||
|
rootPath := os.Getenv("ROOT_PATH")
|
||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
Port: port,
|
Port: port,
|
||||||
Geoip: geoipDbfile,
|
Geoip: geoipDbfile,
|
||||||
CountryBlacklist: strings.Split(countryBlacklist, ","),
|
CountryBlacklist: strings.Split(countryBlacklist, ","),
|
||||||
PgDsn: pgDsn,
|
PgDsn: pgDsn,
|
||||||
|
RootPath: rootPath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ func GetIPInfo(ip string, db *geoip2.Reader) *IpInfo {
|
|||||||
country := func(ip net.IP) string {
|
country := func(ip net.IP) string {
|
||||||
country, _ := db.Country(parsedIp)
|
country, _ := db.Country(parsedIp)
|
||||||
|
|
||||||
println(country.Country.IsoCode)
|
|
||||||
|
|
||||||
if country != nil && country.Country.IsoCode != "" {
|
if country != nil && country.Country.IsoCode != "" {
|
||||||
println(country.Country.IsoCode)
|
|
||||||
return country.Country.IsoCode
|
return country.Country.IsoCode
|
||||||
} else {
|
} else {
|
||||||
return "ZZ"
|
return "ZZ"
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
|
|
||||||
// GenerateHostKey는 'keys' 디렉토리를 생성하고, RSA, ECDSA, Ed25519 호스트 개인 키를 생성하여 저장합니다.
|
// GenerateHostKey는 'keys' 디렉토리를 생성하고, RSA, ECDSA, Ed25519 호스트 개인 키를 생성하여 저장합니다.
|
||||||
// 개인 키는 OpenSSH 형식으로 암호화되어 저장됩니다.
|
// 개인 키는 OpenSSH 형식으로 암호화되어 저장됩니다.
|
||||||
func GenerateHostKey() error {
|
func GenerateHostKey(rootPath string) error {
|
||||||
const keyDir = "./keys"
|
keyDir := rootPath + "/keys"
|
||||||
|
|
||||||
// 1. 키 디렉토리 생성
|
// 1. 키 디렉토리 생성
|
||||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||||
@@ -103,25 +103,27 @@ func generateAndSaveKey(path string, keyType string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckHostKey() ([]ssh.Signer, error) {
|
func CheckHostKey(rootPath string) ([]ssh.Signer, error) {
|
||||||
keyFiles := []string{"./keys/id_rsa", "./keys/id_ecdsa", "./keys/id_ed25519"}
|
keyFiles := []string{"keys/id_rsa", "keys/id_ecdsa", "keys/id_ed25519"}
|
||||||
|
|
||||||
for _, keyFile := range keyFiles {
|
for _, keyFile := range keyFiles {
|
||||||
if _, err := os.Stat(keyFile); os.IsNotExist(err) {
|
tmp := rootPath + "/" + keyFile
|
||||||
return nil, fmt.Errorf("key file %s does not exist", keyFile)
|
if _, err := os.Stat(tmp); os.IsNotExist(err) {
|
||||||
|
return nil, fmt.Errorf("key file %s does not exist", tmp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys = make([]ssh.Signer, 0)
|
var keys = make([]ssh.Signer, 0)
|
||||||
for _, keyFile := range keyFiles {
|
for _, keyFile := range keyFiles {
|
||||||
keyBytes, err := os.ReadFile(keyFile)
|
tmp := rootPath + "/" + keyFile
|
||||||
|
keyBytes, err := os.ReadFile(tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read key file %s: %v", keyFile, err)
|
return nil, fmt.Errorf("failed to read key file %s: %v", tmp, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
signer, err := ssh.ParsePrivateKey(keyBytes)
|
signer, err := ssh.ParsePrivateKey(keyBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse private key %s: %v", keyFile, err)
|
return nil, fmt.Errorf("failed to parse private key %s: %v", tmp, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
keys = append(keys, signer)
|
keys = append(keys, signer)
|
||||||
|
|||||||
Reference in New Issue
Block a user