Merge pull request #13 from retrozenith/docker

feat: add docker support and CI/CD
This commit is contained in:
Nicat Abushov
2025-12-28 17:38:46 +04:00
committed by GitHub
6 changed files with 282 additions and 2 deletions

54
.dockerignore Normal file
View File

@@ -0,0 +1,54 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Build outputs
.next
out
dist
build
# Git
.git
.gitignore
.gitattributes
# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE and editors
.vscode
.idea
*.swp
*.swo
*~
.DS_Store
# Documentation
README.md
CONTRIBUTING.md
CODE_OF_CONDUCT.md
LICENSE
# Screenshots and media
src/screenshots
*.png
*.jpg
*.jpeg
*.gif
*.svg
TUXMATE.png
# Testing
coverage
.nyc_output
# Misc
*.log
.cache

70
.github/workflows/docker-build.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: Docker Build and Push
on:
push:
branches:
- main
- docker
tags:
- "v*"
pull_request:
branches:
- main
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
build-args: |
NEXT_TELEMETRY_DISABLED=1
- name: Image digest
run: echo ${{ steps.meta.outputs.digest }}

63
Dockerfile Normal file
View File

@@ -0,0 +1,63 @@
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
# Copy package files
COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci --only=production && \
npm cache clean --force
# Stage 2: Build the application
FROM node:20-alpine AS builder
WORKDIR /app
# Disable Next.js telemetry during build
ENV NEXT_TELEMETRY_DISABLED=1
# Copy package files
COPY package.json package-lock.json ./
# Install all dependencies (including devDependencies)
RUN npm ci
# Copy source code
COPY . .
# Build Next.js application
RUN npm run build
# Stage 3: Production runtime
FROM node:20-alpine AS runner
WORKDIR /app
# Set environment to production
ENV NODE_ENV=production
# Disable Next.js telemetry
ENV NEXT_TELEMETRY_DISABLED=1
# Create non-root user for security
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Set correct permissions
RUN chown -R nextjs:nodejs /app
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
# Set environment variable for port
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Start the application
CMD ["node", "server.js"]

View File

@@ -81,6 +81,76 @@ npm start
</details>
<details>
<summary><h2>🐳 Docker Deployment</h2></summary>
### Quick Start with Docker
```bash
# Build the Docker image
docker build -t tuxmate:latest .
# Run the container
docker run -p 3000:3000 tuxmate:latest
```
### Using Pre-built Images
Pre-built Docker images are automatically published to GitHub Container Registry:
```bash
# Pull and run the latest image
docker pull ghcr.io/abusoww/tuxmate:latest
docker run -p 3000:3000 ghcr.io/abusoww/tuxmate:latest
# Or use a specific version
docker pull ghcr.io/abusoww/tuxmate:v1.0.0
docker run -p 3000:3000 ghcr.io/abusoww/tuxmate:v1.0.0
```
### Using Docker Compose (Recommended)
```bash
# Start the application
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the application
docker-compose down
```
Open [http://localhost:3000](http://localhost:3000)
### Configuration
The Docker container exposes port 3000 by default. You can customize the port mapping:
```bash
docker run -p 8080:3000 tuxmate:latest
```
### Environment Variables
The following environment variables are configured by default:
- `NODE_ENV=production` - Run in production mode
- `PORT=3000` - Application port
- `NEXT_TELEMETRY_DISABLED=1` - Disable Next.js anonymous telemetry
You can override these when running the container:
```bash
docker run -p 3000:3000 \
-e PORT=3000 \
-e NEXT_TELEMETRY_DISABLED=1 \
tuxmate:latest
```
</details>
## 🛠️ Tech Stack
- Next.js 16
@@ -117,13 +187,14 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
- [x] Copy command & Download script
- [x] Package availability indicators
- [x] Custom domain
- [x] Docker support for containerized deployment
- [x] CI/CD workflow for automated Docker builds
### Planned
- [ ] Search & filter applications
- [ ] Winget support (Windows)
- [ ] Homebrew support (macOS)
- [ ] Dockerfile for containerized deployment
- [ ] Save custom presets / profiles
- [ ] Share configurations via URL
- [ ] More distros (Gentoo, Void, Alpine)

22
docker-compose.yml Normal file
View File

@@ -0,0 +1,22 @@
version: '3.8'
services:
tuxmate:
build:
context: .
dockerfile: Dockerfile
image: ghcr.io/retrozenith/tuxmate:latest
container_name: tuxmate
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- NEXT_TELEMETRY_DISABLED=1
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

View File

@@ -1,7 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: 'standalone',
};
export default nextConfig;