mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
Enhance Docker and Build Configuration
- Added support for build arguments in Dockerfile to specify UID, GID, version, build time, and commit hash. - Updated docker-compose.yaml to utilize UID and GID for non-root user execution, improving file permission handling. - Introduced entrypoint.sh script to manage user permissions and environment setup at container startup. - Enhanced application logging to include version information during startup. - Updated README with new instructions for running the application with specific user IDs and environment variables.
This commit is contained in:
@@ -26,6 +26,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Needed to get all tags for versioning
|
||||||
|
|
||||||
|
# Set version information
|
||||||
|
- name: Set Version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.event.inputs.manual_version }}" != "" ]]; then
|
||||||
|
echo "VERSION=${{ github.event.inputs.manual_version }}" >> $GITHUB_ENV
|
||||||
|
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/}
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev")-$(git rev-parse --short HEAD)
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
echo "BUILD_TIME=$(date -u +'%Y-%m-%d_%H:%M:%S')" >> $GITHUB_ENV
|
||||||
|
echo "COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
# Set up Docker Buildx for efficient builds
|
# Set up Docker Buildx for efficient builds
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@@ -61,5 +79,11 @@ jobs:
|
|||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ env.VERSION }}
|
||||||
|
BUILD_TIME=${{ env.BUILD_TIME }}
|
||||||
|
COMMIT=${{ env.COMMIT }}
|
||||||
|
UID=1000
|
||||||
|
GID=1000
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
@@ -27,6 +27,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Needed to get all tags for versioning
|
||||||
|
|
||||||
|
# Set version information
|
||||||
|
- name: Set Version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.event.inputs.manual_version }}" != "" ]]; then
|
||||||
|
echo "VERSION=${{ github.event.inputs.manual_version }}" >> $GITHUB_ENV
|
||||||
|
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/}
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev")-$(git rev-parse --short HEAD)
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
echo "BUILD_TIME=$(date -u +'%Y-%m-%d_%H:%M:%S')" >> $GITHUB_ENV
|
||||||
|
echo "COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
# Set up Docker Buildx for efficient builds
|
# Set up Docker Buildx for efficient builds
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@@ -62,5 +80,11 @@ jobs:
|
|||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ env.VERSION }}
|
||||||
|
BUILD_TIME=${{ env.BUILD_TIME }}
|
||||||
|
COMMIT=${{ env.COMMIT }}
|
||||||
|
UID=1000
|
||||||
|
GID=1000
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
@@ -57,23 +57,29 @@ jobs:
|
|||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
# Also set build timestamp for versioning
|
||||||
|
echo "BUILD_TIME=$(date -u +'%Y-%m-%d_%H:%M:%S')" >> $GITHUB_ENV
|
||||||
|
echo "COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build for multiple platforms
|
- name: Build for multiple platforms
|
||||||
run: |
|
run: |
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
|
|
||||||
|
# Define common ldflags with version information
|
||||||
|
LDFLAGS="-X github.com/starfleetcptn/gomft/components.AppVersion=$VERSION -X main.Version=$VERSION -X main.BuildTime=$BUILD_TIME -X main.Commit=$COMMIT"
|
||||||
|
|
||||||
# Linux builds
|
# Linux builds
|
||||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-linux-amd64 .
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-linux-amd64 .
|
||||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-linux-arm64 .
|
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-linux-arm64 .
|
||||||
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-linux-armv7 .
|
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-linux-armv7 .
|
||||||
|
|
||||||
# macOS builds
|
# macOS builds
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-darwin-amd64 .
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-darwin-amd64 .
|
||||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-darwin-arm64 .
|
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-darwin-arm64 .
|
||||||
|
|
||||||
# Windows builds
|
# Windows builds
|
||||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-windows-amd64.exe .
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-windows-amd64.exe .
|
||||||
GOOS=windows GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-X main.version=$VERSION" -o dist/gomft-$VERSION-windows-arm64.exe .
|
GOOS=windows GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o dist/gomft-$VERSION-windows-arm64.exe .
|
||||||
|
|
||||||
# Create checksums
|
# Create checksums
|
||||||
cd dist
|
cd dist
|
||||||
|
|||||||
+34
-3
@@ -2,6 +2,11 @@ FROM golang:1.24-alpine AS builder
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Accept build arguments for version information
|
||||||
|
ARG VERSION=dev
|
||||||
|
ARG BUILD_TIME=unknown
|
||||||
|
ARG COMMIT=unknown
|
||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN apk add --no-cache git build-base
|
RUN apk add --no-cache git build-base
|
||||||
|
|
||||||
@@ -18,8 +23,10 @@ COPY . .
|
|||||||
# Generate template files from .templ files
|
# Generate template files from .templ files
|
||||||
RUN templ generate
|
RUN templ generate
|
||||||
|
|
||||||
# Build the application
|
# Compile the application with version information
|
||||||
RUN CGO_ENABLED=1 GOOS=linux go build -o gomft
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
|
-ldflags "-X github.com/starfleetcptn/gomft/components.AppVersion=${VERSION} -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.Commit=${COMMIT} -X github.com/starfleetcptn/gomft/components.BuildTime=${BUILD_TIME} -X github.com/starfleetcptn/gomft/components.Commit=${COMMIT}" \
|
||||||
|
-o /app/gomft
|
||||||
|
|
||||||
# Install rclone
|
# Install rclone
|
||||||
RUN apk add --no-cache curl unzip && \
|
RUN apk add --no-cache curl unzip && \
|
||||||
@@ -34,10 +41,21 @@ RUN apk add --no-cache curl unzip && \
|
|||||||
# Create a smaller runtime image
|
# Create a smaller runtime image
|
||||||
FROM alpine:3.19
|
FROM alpine:3.19
|
||||||
|
|
||||||
|
# Add arguments for UID and GID with defaults
|
||||||
|
ARG UID=1000
|
||||||
|
ARG GID=1000
|
||||||
|
ARG USERNAME=gomft
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN apk add --no-cache ca-certificates tzdata sqlite bash
|
RUN apk add --no-cache ca-certificates tzdata sqlite bash shadow su-exec \
|
||||||
|
&& apk add --no-cache --virtual .user-deps \
|
||||||
|
shadow curl xz
|
||||||
|
|
||||||
|
# Create user and group with specified IDs
|
||||||
|
RUN addgroup -g ${GID} ${USERNAME} && \
|
||||||
|
adduser -D -u ${UID} -G ${USERNAME} -s /bin/sh ${USERNAME}
|
||||||
|
|
||||||
# Copy the binary from the builder stage
|
# Copy the binary from the builder stage
|
||||||
COPY --from=builder /app/gomft /app/
|
COPY --from=builder /app/gomft /app/
|
||||||
@@ -47,14 +65,27 @@ COPY --from=builder /usr/local/bin/rclone /usr/local/bin/rclone
|
|||||||
COPY static/ /app/static/
|
COPY static/ /app/static/
|
||||||
COPY components/ /app/components/
|
COPY components/ /app/components/
|
||||||
|
|
||||||
|
# Copy entrypoint script
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
# Create data and backup directories
|
# Create data and backup directories
|
||||||
RUN mkdir -p /app/data /app/backups
|
RUN mkdir -p /app/data /app/backups
|
||||||
|
|
||||||
|
# Create a placeholder .env file with proper permissions
|
||||||
|
RUN touch /app/.env && chmod 644 /app/.env && chown ${USERNAME}:${USERNAME} /app/.env
|
||||||
|
|
||||||
# Set executable permissions
|
# Set executable permissions
|
||||||
RUN chmod +x /app/gomft
|
RUN chmod +x /app/gomft
|
||||||
|
|
||||||
|
# Set ownership of application files
|
||||||
|
RUN chown -R ${USERNAME}:${USERNAME} /app
|
||||||
|
|
||||||
# Expose the application port
|
# Expose the application port
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Use our entrypoint script
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
CMD ["/app/gomft"]
|
CMD ["/app/gomft"]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ GoMFT is a web-based managed file transfer application built with Go, leveraging
|
|||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> This application is actively under development. As such, any aspect of the application—including configurations, data structures, and database fields—may change rapidly and without prior notice. Please review all release notes thoroughly before updating.
|
> This application is actively under development. As such, any aspect of the application—including configurations, data structures, and database fields—may change rapidly and without prior notice. Please review all release notes thoroughly before updating.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
@@ -29,6 +30,8 @@ GoMFT is a web-based managed file transfer application built with Go, leveraging
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Multiple Storage Support**: Leverage rclone's extensive support for cloud storage providers:
|
- **Multiple Storage Support**: Leverage rclone's extensive support for cloud storage providers:
|
||||||
@@ -80,12 +83,16 @@ GoMFT is a web-based managed file transfer application built with Go, leveraging
|
|||||||
- **Docker Support**: Easy deployment with Docker images and Docker Compose support
|
- **Docker Support**: Easy deployment with Docker images and Docker Compose support
|
||||||
- **Portable Deployment**: Run on any platform that supports Docker or Go
|
- **Portable Deployment**: Run on any platform that supports Docker or Go
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Go 1.21 or later
|
- Go 1.21 or later
|
||||||
- rclone installed and configured
|
- rclone installed and configured
|
||||||
- SQLite 3
|
- SQLite 3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Standard Installation
|
### Standard Installation
|
||||||
@@ -116,6 +123,8 @@ docker pull starfleetcptn/gomft:latest
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. Run the container:
|
2. Run the container:
|
||||||
|
|
||||||
|
#### Basic run
|
||||||
```bash
|
```bash
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name gomft \
|
--name gomft \
|
||||||
@@ -125,6 +134,42 @@ docker run -d \
|
|||||||
starfleetcptn/gomft:latest
|
starfleetcptn/gomft:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Run with specific user ID and group ID (using environment variables)
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name gomft \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-v /path/to/data:/app/data \
|
||||||
|
-v /path/to/backups:/app/backups \
|
||||||
|
-e PUID=$(id -u) \
|
||||||
|
-e PGID=$(id -g) \
|
||||||
|
starfleetcptn/gomft:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Or specify user IDs directly
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name gomft \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-v /path/to/data:/app/data \
|
||||||
|
-v /path/to/backups:/app/backups \
|
||||||
|
-e PUID=1001 \
|
||||||
|
-e PGID=1001 \
|
||||||
|
starfleetcptn/gomft:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using a .env file for configuration
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name gomft \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-v /path/to/data:/app/data \
|
||||||
|
-v /path/to/backups:/app/backups \
|
||||||
|
-v /path/to/.env:/app/.env \
|
||||||
|
-e PUID=$(id -u) \
|
||||||
|
-e PGID=$(id -g) \
|
||||||
|
starfleetcptn/gomft:latest
|
||||||
|
```
|
||||||
3. Access the web interface at `http://localhost:8080`
|
3. Access the web interface at `http://localhost:8080`
|
||||||
|
|
||||||
#### Docker Compose Example
|
#### Docker Compose Example
|
||||||
@@ -143,19 +188,19 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
- ./backups:/app/backups
|
- ./backups:/app/backups
|
||||||
|
- ./.env:/app/.env
|
||||||
environment:
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
- TZ=UTC
|
- TZ=UTC
|
||||||
- SERVER_ADDRESS=:8080
|
- SERVER_ADDRESS=:8080
|
||||||
- DATA_DIR=/app/data
|
- DATA_DIR=/app/data
|
||||||
- BACKUP_DIR=/app/backups
|
- BACKUP_DIR=/app/backups
|
||||||
- JWT_SECRET=change_this_to_a_secure_random_string
|
- JWT_SECRET=change_this_to_a_secure_random_string
|
||||||
- BASE_URL=http://localhost:8080
|
- BASE_URL=http://localhost:8080
|
||||||
# Google OAuth configuration (optional)
|
|
||||||
- GOOGLE_CLIENT_ID=your_google_client_id
|
- GOOGLE_CLIENT_ID=your_google_client_id
|
||||||
- GOOGLE_CLIENT_SECRET=your_google_client_secret
|
- GOOGLE_CLIENT_SECRET=your_google_client_secret
|
||||||
# Two-Factor Authentication configuration
|
- TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
||||||
- TOTP_ENCRYPTION_KEY=your_32_byte_secure_encryption_key
|
|
||||||
# Email configuration
|
|
||||||
- EMAIL_ENABLED=true
|
- EMAIL_ENABLED=true
|
||||||
- EMAIL_HOST=smtp.example.com
|
- EMAIL_HOST=smtp.example.com
|
||||||
- EMAIL_PORT=587
|
- EMAIL_PORT=587
|
||||||
@@ -165,34 +210,14 @@ services:
|
|||||||
- EMAIL_REQUIRE_AUTH=true
|
- EMAIL_REQUIRE_AUTH=true
|
||||||
- EMAIL_USERNAME=smtp_username
|
- EMAIL_USERNAME=smtp_username
|
||||||
- EMAIL_PASSWORD=smtp_password
|
- EMAIL_PASSWORD=smtp_password
|
||||||
# Logging configuration
|
|
||||||
- LOGS_DIR=/app/data/logs
|
- LOGS_DIR=/app/data/logs
|
||||||
- LOG_MAX_SIZE=10
|
- LOG_MAX_SIZE=10
|
||||||
- LOG_MAX_BACKUPS=5
|
- LOG_MAX_BACKUPS=5
|
||||||
- LOG_MAX_AGE=30
|
- LOG_MAX_AGE=30
|
||||||
- LOG_COMPRESS=true
|
- LOG_COMPRESS=true
|
||||||
- LOG_LEVEL=info
|
- LOG_LEVEL=info
|
||||||
|
# The user directive is no longer needed when using PUID/PGID environment variables
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can mount your own .env file to the container:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
version: '3'
|
|
||||||
services:
|
|
||||||
gomft:
|
|
||||||
image: starfleetcptn/gomft:latest
|
|
||||||
container_name: gomft
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
volumes:
|
|
||||||
- ./data:/app/data
|
|
||||||
- ./backups:/app/backups
|
|
||||||
- ./.env:/app/.env
|
|
||||||
environment:
|
|
||||||
- TZ=UTC
|
|
||||||
```
|
|
||||||
|
|
||||||
Save this as `docker-compose.yml` and run:
|
Save this as `docker-compose.yml` and run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -201,11 +226,14 @@ docker-compose up -d
|
|||||||
|
|
||||||
For more information and available tags, visit the [GoMFT Docker Hub page](https://hub.docker.com/r/starfleetcptn/gomft).
|
For more information and available tags, visit the [GoMFT Docker Hub page](https://hub.docker.com/r/starfleetcptn/gomft).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
GoMFT uses an environment file located at `.env` in the root directory of the application. On first run, a default configuration will be created:
|
GoMFT uses an environment file located at `.env` in the root directory of the application. On first run, a default configuration will be created:
|
||||||
|
|
||||||
```
|
```ini
|
||||||
|
# Basic configuration
|
||||||
SERVER_ADDRESS=:8080
|
SERVER_ADDRESS=:8080
|
||||||
DATA_DIR=/app/data
|
DATA_DIR=/app/data
|
||||||
BACKUP_DIR=/app/backups
|
BACKUP_DIR=/app/backups
|
||||||
@@ -230,6 +258,10 @@ EMAIL_PASSWORD=smtp_password
|
|||||||
|
|
||||||
# Two-Factor Authentication configuration
|
# Two-Factor Authentication configuration
|
||||||
TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
TOTP_ENCRYPTION_KEY=your_32_byte_encryption_key_here
|
||||||
|
|
||||||
|
# UserID and GroupID
|
||||||
|
PUID=1000
|
||||||
|
PGID=1000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration Options
|
### Configuration Options
|
||||||
@@ -278,6 +310,8 @@ GoMFT provides configurable logging with rotation support through the following
|
|||||||
|
|
||||||
Log files contain detailed information about file transfers, job execution, and system operations, which can be useful for troubleshooting and auditing.
|
Log files contain detailed information about file transfers, job execution, and system operations, which can be useful for troubleshooting and auditing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. Start the server:
|
1. Start the server:
|
||||||
@@ -552,6 +586,8 @@ The Admin Tools interface also includes database management capabilities:
|
|||||||
- View system statistics
|
- View system statistics
|
||||||
- Optimize the database with maintenance tools
|
- Optimize the database with maintenance tools
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Project Structure
|
### Project Structure
|
||||||
@@ -602,6 +638,8 @@ templ generate
|
|||||||
air
|
air
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. Fork the repository
|
1. Fork the repository
|
||||||
@@ -610,6 +648,8 @@ air
|
|||||||
4. Push to the branch
|
4. Push to the branch
|
||||||
5. Create a Pull Request
|
5. Create a Pull Request
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Directory Structure
|
## Directory Structure
|
||||||
|
|
||||||
GoMFT uses the following directory structure:
|
GoMFT uses the following directory structure:
|
||||||
@@ -630,6 +670,83 @@ volumes:
|
|||||||
|
|
||||||
These paths can be customized using the environment variables `DATA_DIR`, `BACKUP_DIR`, and `LOGS_DIR`.
|
These paths can be customized using the environment variables `DATA_DIR`, `BACKUP_DIR`, and `LOGS_DIR`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Running as a Non-Root User
|
||||||
|
|
||||||
|
By default, Docker containers run as the root user, which can pose security risks. GoMFT supports running as a non-root user, which is recommended for production environments.
|
||||||
|
|
||||||
|
#### Benefits of Running as Non-Root
|
||||||
|
|
||||||
|
- **Improved Security**: Limits the potential damage if the container is compromised
|
||||||
|
- **Better File Permissions**: Files created by the container will match your host user permissions
|
||||||
|
- **Compliance**: Many security policies and best practices require containers to run as non-root
|
||||||
|
|
||||||
|
#### Methods to Run as Non-Root
|
||||||
|
|
||||||
|
1. **Using PUID/PGID environment variables (recommended)**:
|
||||||
|
```bash
|
||||||
|
# Using current user's ID
|
||||||
|
docker run -e PUID=$(id -u) -e PGID=$(id -g) starfleetcptn/gomft:latest
|
||||||
|
|
||||||
|
# Or in docker-compose.yml
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
```
|
||||||
|
This is the most flexible method as it allows changing the user at runtime without rebuilding the image.
|
||||||
|
|
||||||
|
2. **Using the `--user` flag with Docker run**:
|
||||||
|
```bash
|
||||||
|
docker run --user $(id -u):$(id -g) starfleetcptn/gomft:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Using Docker Compose with environment variables for `user` directive**:
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
gomft:
|
||||||
|
image: starfleetcptn/gomft:latest
|
||||||
|
user: "${UID:-1000}:${GID:-1000}"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Building a custom image with specified UID/GID**:
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
gomft:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
UID: ${UID:-1000}
|
||||||
|
GID: ${GID:-1000}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Environment Variables for User Management
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `PUID` | User ID to run as | Built-in user ID (1000) |
|
||||||
|
| `PGID` | Group ID to run as | Built-in group ID (1000) |
|
||||||
|
| `USERNAME` | Username to use | `gomft` |
|
||||||
|
|
||||||
|
These environment variables allow you to change the user/group IDs at runtime without rebuilding the image.
|
||||||
|
|
||||||
|
#### Volume Permissions
|
||||||
|
|
||||||
|
When mounting volumes, ensure that the directories on the host have appropriate permissions for the container user:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create directories with correct ownership
|
||||||
|
mkdir -p data backups
|
||||||
|
chown -R $(id -u):$(id -g) data backups
|
||||||
|
|
||||||
|
# Or adjust permissions to allow the container user to write
|
||||||
|
mkdir -p data backups
|
||||||
|
chmod -R 777 data backups # Less secure, but easier for testing
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -513,11 +513,96 @@ templ AdminTools(ctx context.Context, data AdminToolsData) {
|
|||||||
{ fmt.Sprint(data.TotalJobs) }
|
{ fmt.Sprint(data.TotalJobs) }
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="sm:col-span-1">
|
||||||
|
<dt class="text-sm font-medium text-secondary-500 dark:text-secondary-400">Application Version</dt>
|
||||||
|
<dd class="mt-1 text-sm text-secondary-900 dark:text-secondary-100">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span>{ AppVersion }</span>
|
||||||
|
if AppVersion == "dev" {
|
||||||
|
<a href="https://github.com/starfleetcptn/gomft/releases"
|
||||||
|
class="ml-2 text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300"
|
||||||
|
target="_blank" rel="noopener">
|
||||||
|
<i class="fas fa-external-link-alt text-xs"></i>
|
||||||
|
</a>
|
||||||
|
} else if AppVersion == "1.0.0" {
|
||||||
|
<a href="https://github.com/starfleetcptn/gomft/releases/tag/v1.0.0"
|
||||||
|
class="ml-2 text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300"
|
||||||
|
target="_blank" rel="noopener">
|
||||||
|
<i class="fas fa-external-link-alt text-xs"></i>
|
||||||
|
</a>
|
||||||
|
} else if AppVersion == "1.1.0" {
|
||||||
|
<a href="https://github.com/starfleetcptn/gomft/releases/tag/v1.1.0"
|
||||||
|
class="ml-2 text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300"
|
||||||
|
target="_blank" rel="noopener">
|
||||||
|
<i class="fas fa-external-link-alt text-xs"></i>
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<a href="https://github.com/starfleetcptn/gomft/releases"
|
||||||
|
class="ml-2 text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300"
|
||||||
|
target="_blank" rel="noopener">
|
||||||
|
<i class="fas fa-external-link-alt text-xs"></i>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Build Information -->
|
||||||
|
<div class="mt-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="text-lg font-medium text-secondary-900 dark:text-secondary-100">
|
||||||
|
<i class="fas fa-code-branch mr-2 text-primary-500"></i>
|
||||||
|
Build Information
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="relative overflow-hidden bg-secondary-50 dark:bg-secondary-900 rounded-lg">
|
||||||
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
<dl class="grid grid-cols-1 gap-x-4 gap-y-6 sm:grid-cols-3">
|
||||||
|
<div class="sm:col-span-1">
|
||||||
|
<dt class="text-sm font-medium text-secondary-500 dark:text-secondary-400">Version</dt>
|
||||||
|
<dd class="mt-1 text-sm text-secondary-900 dark:text-secondary-100 font-mono">
|
||||||
|
{ AppVersion }
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm:col-span-1">
|
||||||
|
<dt class="text-sm font-medium text-secondary-500 dark:text-secondary-400">Build Time</dt>
|
||||||
|
<dd class="mt-1 text-sm text-secondary-900 dark:text-secondary-100 font-mono">
|
||||||
|
{ getBuildTime() }
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm:col-span-1">
|
||||||
|
<dt class="text-sm font-medium text-secondary-500 dark:text-secondary-400">Commit</dt>
|
||||||
|
<dd class="mt-1 text-sm text-secondary-900 dark:text-secondary-100 font-mono">
|
||||||
|
{ getCommit() }
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<a
|
||||||
|
href="https://github.com/starfleetcptn/gomft"
|
||||||
|
class="inline-flex items-center px-4 py-2 text-sm text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300 transition-colors"
|
||||||
|
target="_blank" rel="noopener"
|
||||||
|
>
|
||||||
|
<i class="fab fa-github mr-2"></i>
|
||||||
|
View on GitHub
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Log Viewer -->
|
<!-- Log Viewer -->
|
||||||
<div id="logs-container" class="mt-8">
|
<div id="logs-container" class="mt-8">
|
||||||
@AdminLogViewer(data)
|
@AdminLogViewer(data)
|
||||||
@@ -897,3 +982,21 @@ templ AdminLogContent(data AdminToolsData) {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBuildTime returns the build time of the application
|
||||||
|
// This can be set using ldflags during build
|
||||||
|
// Example: go build -ldflags "-X github.com/starfleetcptn/gomft/components.BuildTime=2023-01-01T00:00:00Z"
|
||||||
|
var BuildTime = "unknown"
|
||||||
|
|
||||||
|
func getBuildTime() string {
|
||||||
|
return BuildTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCommit returns the commit hash of the application
|
||||||
|
// This can be set using ldflags during build
|
||||||
|
// Example: go build -ldflags "-X github.com/starfleetcptn/gomft/components.Commit=abcdef123456"
|
||||||
|
var Commit = "unknown"
|
||||||
|
|
||||||
|
func getCommit() string {
|
||||||
|
return Commit
|
||||||
|
}
|
||||||
|
|||||||
+25
-1
@@ -3,8 +3,20 @@ package components
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AppVersion will be set at build time using ldflags
|
||||||
|
// Example build command:
|
||||||
|
// go build -ldflags "-X github.com/starfleetcptn/gomft/components.AppVersion=1.2.3"
|
||||||
|
var AppVersion = "dev"
|
||||||
|
|
||||||
|
// GetReleaseURL returns the URL to the specific GitHub release
|
||||||
|
func GetReleaseURL() templ.SafeURL {
|
||||||
|
return templ.SafeURL(fmt.Sprintf("https://github.com/starfleetcptn/gomft/releases/tag/v%s", AppVersion))
|
||||||
|
}
|
||||||
|
|
||||||
// CreateTemplateContext creates a new context with user information from Gin's context
|
// CreateTemplateContext creates a new context with user information from Gin's context
|
||||||
func CreateTemplateContext(c *gin.Context) context.Context {
|
func CreateTemplateContext(c *gin.Context) context.Context {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -437,6 +449,18 @@ templ LayoutWithContext(title string, ctx context.Context) {
|
|||||||
<p class="text-center text-sm text-secondary-500 dark:text-secondary-400">
|
<p class="text-center text-sm text-secondary-500 dark:text-secondary-400">
|
||||||
GoMFT © { getCurrentYear() } | Secure File Transfer Solution
|
GoMFT © { getCurrentYear() } | Secure File Transfer Solution
|
||||||
</p>
|
</p>
|
||||||
|
<div class="flex justify-center items-center space-x-4 mt-1">
|
||||||
|
<p class="text-xs text-secondary-400 dark:text-secondary-500">
|
||||||
|
<a href="https://github.com/starfleetcptn/gomft" class="hover:text-primary-600 dark:hover:text-primary-400 transition-colors duration-200" target="_blank" rel="noopener">
|
||||||
|
<i class="fab fa-github mr-1"></i>GitHub
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-secondary-400 dark:text-secondary-500">
|
||||||
|
<a href={ GetReleaseURL() } class="hover:text-primary-600 dark:hover:text-primary-400 transition-colors duration-200" target="_blank" rel="noopener">
|
||||||
|
<i class="fas fa-tag mr-1"></i>Version { AppVersion }
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
@@ -544,5 +568,5 @@ func getUserEmail(ctx context.Context) string {
|
|||||||
|
|
||||||
// Helper function to get current year
|
// Helper function to get current year
|
||||||
func getCurrentYear() string {
|
func getCurrentYear() string {
|
||||||
return "2025"
|
return time.Now().Format("2006")
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,15 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
# Set the UID/GID to match your host user for better file permissions
|
||||||
|
# Default is 1000:1000 if not specified
|
||||||
|
UID: ${UID:-1000}
|
||||||
|
GID: ${GID:-1000}
|
||||||
|
# Version information
|
||||||
|
VERSION: ${VERSION:-dev}
|
||||||
|
BUILD_TIME: ${BUILD_TIME:-unknown}
|
||||||
|
COMMIT: ${COMMIT:-unknown}
|
||||||
container_name: gomft
|
container_name: gomft
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
@@ -22,6 +31,9 @@ services:
|
|||||||
# - LOG_LEVEL=info
|
# - LOG_LEVEL=info
|
||||||
networks:
|
networks:
|
||||||
- gomft-network
|
- gomft-network
|
||||||
|
# For non-root installs, the container needs to run with the same UID
|
||||||
|
# as the host user to access mounted volumes properly
|
||||||
|
user: ${UID:-1000}:${GID:-1000}
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
gomft-network:
|
gomft-network:
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Default username
|
||||||
|
USERNAME=${USERNAME:-gomft}
|
||||||
|
|
||||||
|
# If PUID/PGID env vars are set, update the user's UID/GID
|
||||||
|
if [ -n "${PUID}" ] && [ -n "${PGID}" ]; then
|
||||||
|
echo "🔒 Updating user ${USERNAME} with UID:GID = ${PUID}:${PGID}"
|
||||||
|
|
||||||
|
# Make sure we have directories to work with
|
||||||
|
mkdir -p /app/data /app/backups
|
||||||
|
|
||||||
|
# Check if we're on Alpine (busybox)
|
||||||
|
if grep -q "Alpine" /etc/os-release 2>/dev/null; then
|
||||||
|
echo "Detected Alpine Linux, using busybox usermod/groupmod..."
|
||||||
|
|
||||||
|
# Update group ID first
|
||||||
|
if [ "$(getent group ${USERNAME} | cut -d: -f3)" != "${PGID}" ]; then
|
||||||
|
echo "Updating GID to ${PGID}..."
|
||||||
|
groupmod -g ${PGID} ${USERNAME} || echo "⚠️ Failed to change GID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update user ID
|
||||||
|
if [ "$(id -u ${USERNAME})" != "${PUID}" ]; then
|
||||||
|
echo "Updating UID to ${PUID}..."
|
||||||
|
usermod -u ${PUID} ${USERNAME} || echo "⚠️ Failed to change UID"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Non-Alpine system, using standard user management..."
|
||||||
|
# Handle user/group changes with error recovery
|
||||||
|
{
|
||||||
|
# First remove the user (since user has the group as primary group)
|
||||||
|
if getent passwd ${USERNAME} > /dev/null; then
|
||||||
|
echo "Removing existing user ${USERNAME}"
|
||||||
|
userdel ${USERNAME} 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait a moment for system to clean up user
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Then remove the group
|
||||||
|
if getent group ${USERNAME} > /dev/null; then
|
||||||
|
echo "Removing existing group ${USERNAME}"
|
||||||
|
groupdel ${USERNAME} 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recreate group and user in the correct order
|
||||||
|
echo "Creating group ${USERNAME} with GID ${PGID}"
|
||||||
|
groupadd -g ${PGID} ${USERNAME} 2>/dev/null || groupadd ${USERNAME} 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Creating user ${USERNAME} with UID ${PUID}"
|
||||||
|
useradd -u ${PUID} -g ${USERNAME} -s /bin/sh ${USERNAME} 2>/dev/null ||
|
||||||
|
useradd -g ${USERNAME} -s /bin/sh ${USERNAME} 2>/dev/null || true
|
||||||
|
} || {
|
||||||
|
echo "⚠️ Warning: Failed to update UID/GID, continuing with built-in user"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fix ownership of app directories
|
||||||
|
echo "Setting ownership of app directories"
|
||||||
|
chown -R ${USERNAME}:${USERNAME} /app/data /app/backups || echo "⚠️ Warning: Failed to change ownership"
|
||||||
|
|
||||||
|
# Ensure .env file exists and has correct permissions
|
||||||
|
if [ -f /app/.env ]; then
|
||||||
|
echo "Found .env file, setting permissions..."
|
||||||
|
chown ${USERNAME}:${USERNAME} /app/.env || echo "⚠️ Warning: Failed to change .env ownership"
|
||||||
|
chmod 644 /app/.env || echo "⚠️ Warning: Failed to change .env permissions"
|
||||||
|
else
|
||||||
|
echo "No .env file found, creating empty one..."
|
||||||
|
touch /app/.env
|
||||||
|
chown ${USERNAME}:${USERNAME} /app/.env || echo "⚠️ Warning: Failed to change .env ownership"
|
||||||
|
chmod 644 /app/.env || echo "⚠️ Warning: Failed to change .env permissions"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the application as the specified user
|
||||||
|
echo "Starting application as user ${USERNAME}"
|
||||||
|
if command -v su-exec >/dev/null 2>&1; then
|
||||||
|
exec su-exec ${USERNAME} "$@"
|
||||||
|
elif command -v gosu >/dev/null 2>&1; then
|
||||||
|
exec gosu ${USERNAME} "$@"
|
||||||
|
else
|
||||||
|
exec su -m ${USERNAME} -c "$*"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Run as the predefined user (set during build)
|
||||||
|
echo "Starting application with predefined user"
|
||||||
|
exec "$@"
|
||||||
|
fi
|
||||||
@@ -3,6 +3,7 @@ package migrations
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gormigrate/gormigrate/v2"
|
"github.com/go-gormigrate/gormigrate/v2"
|
||||||
@@ -33,8 +34,25 @@ func InitialSchema() *gormigrate.Migration {
|
|||||||
return fmt.Errorf("failed to get database path: %v", err)
|
return fmt.Errorf("failed to get database path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create backup file with timestamp
|
// Get backup directory from environment variable or use default
|
||||||
backupFile := fmt.Sprintf("%s.backup.%s", dbPath, time.Now().Format("20060102_150405"))
|
backupDir := os.Getenv("BACKUP_DIR")
|
||||||
|
if backupDir == "" {
|
||||||
|
backupDir = "/app/backups" // Default Docker path
|
||||||
|
// Check if we're not in Docker
|
||||||
|
if _, err := os.Stat(backupDir); os.IsNotExist(err) {
|
||||||
|
backupDir = "backups" // Fallback to local directory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create backup directory if it doesn't exist
|
||||||
|
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create backup directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create backup file with timestamp in the backup directory
|
||||||
|
dbFileName := filepath.Base(dbPath)
|
||||||
|
backupFileName := fmt.Sprintf("%s.backup.%s", dbFileName, time.Now().Format("20060102_150405"))
|
||||||
|
backupFile := filepath.Join(backupDir, backupFileName)
|
||||||
|
|
||||||
// Read original database
|
// Read original database
|
||||||
data, err := os.ReadFile(dbPath)
|
data, err := os.ReadFile(dbPath)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package migrations
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gormigrate/gormigrate/v2"
|
"github.com/go-gormigrate/gormigrate/v2"
|
||||||
@@ -34,8 +35,25 @@ func Add2FA() *gormigrate.Migration {
|
|||||||
return fmt.Errorf("failed to get database path: %v", err)
|
return fmt.Errorf("failed to get database path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create backup file with timestamp
|
// Get backup directory from environment variable or use default
|
||||||
backupFile := fmt.Sprintf("%s.backup.%s", dbPath, time.Now().Format("20060102_150405"))
|
backupDir := os.Getenv("BACKUP_DIR")
|
||||||
|
if backupDir == "" {
|
||||||
|
backupDir = "/app/backups" // Default Docker path
|
||||||
|
// Check if we're not in Docker
|
||||||
|
if _, err := os.Stat(backupDir); os.IsNotExist(err) {
|
||||||
|
backupDir = "backups" // Fallback to local directory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create backup directory if it doesn't exist
|
||||||
|
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create backup directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create backup file with timestamp in the backup directory
|
||||||
|
dbFileName := filepath.Base(dbPath)
|
||||||
|
backupFileName := fmt.Sprintf("%s.backup.%s", dbFileName, time.Now().Format("20060102_150405"))
|
||||||
|
backupFile := filepath.Join(backupDir, backupFileName)
|
||||||
|
|
||||||
// Read original database
|
// Read original database
|
||||||
data, err := os.ReadFile(dbPath)
|
data, err := os.ReadFile(dbPath)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
// "github.com/starfleetcptn/gomft/internal/api"
|
// "github.com/starfleetcptn/gomft/internal/api"
|
||||||
|
"github.com/starfleetcptn/gomft/components"
|
||||||
"github.com/starfleetcptn/gomft/internal/config"
|
"github.com/starfleetcptn/gomft/internal/config"
|
||||||
"github.com/starfleetcptn/gomft/internal/db"
|
"github.com/starfleetcptn/gomft/internal/db"
|
||||||
"github.com/starfleetcptn/gomft/internal/scheduler"
|
"github.com/starfleetcptn/gomft/internal/scheduler"
|
||||||
@@ -27,7 +28,7 @@ func main() {
|
|||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
log.Printf("Starting GoMFT server...")
|
log.Printf("Starting GoMFT server version %s...", components.AppVersion)
|
||||||
|
|
||||||
// Initialize configuration
|
// Initialize configuration
|
||||||
cfg, err := config.Load()
|
cfg, err := config.Load()
|
||||||
|
|||||||
Reference in New Issue
Block a user