Skip to content

Commit 6f839ca

Browse files
fixes
1 parent 8d38451 commit 6f839ca

File tree

8 files changed

+177
-13
lines changed

8 files changed

+177
-13
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
SECRET_KEY=your-very-secret-key-change-this-in-production
55
DATABASE_URL=sqlite:///data/github_backup.db
66

7+
# User/Group IDs for file permissions (run 'id' command to get your values)
8+
PUID=1000
9+
PGID=1000
10+
711
# Optional: If using PostgreSQL instead of SQLite
812
# DATABASE_URL=postgresql://username:password@localhost:5432/github_backup
913

DEPLOYMENT.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ This project is automatically built and published to GitHub Container Registry (
77
### 1. Deploy with Docker Run
88

99
```bash
10+
# Get your user and group IDs
11+
USER_ID=$(id -u)
12+
GROUP_ID=$(id -g)
13+
1014
# Create directories for persistent data
1115
mkdir -p ./data ./backups ./logs
1216

13-
# Run the container
17+
# Run the container with proper user/group IDs
1418
docker run -d \
1519
--name github-backup \
1620
--restart unless-stopped \
@@ -19,6 +23,8 @@ docker run -d \
1923
-v $(pwd)/backups:/app/backups \
2024
-v $(pwd)/logs:/app/logs \
2125
-e SECRET_KEY="$(openssl rand -base64 32)" \
26+
-e PUID=${USER_ID} \
27+
-e PGID=${GROUP_ID} \
2228
ghcr.io/gittimeraider/githubbackup:latest
2329
```
2430

@@ -52,6 +58,9 @@ services:
5258
5359
Then run:
5460
```bash
61+
# Set your user/group IDs and secret key
62+
export PUID=$(id -u)
63+
export PGID=$(id -g)
5564
export SECRET_KEY=$(openssl rand -base64 32)
5665
docker-compose up -d
5766
```
@@ -138,6 +147,10 @@ Create a `.env` file for environment variables:
138147
# Required: Change this in production
139148
SECRET_KEY=your-super-secret-key-here
140149
150+
# User/Group IDs for proper file permissions
151+
PUID=1000 # Your user ID (run 'id -u' to get this)
152+
PGID=1000 # Your group ID (run 'id -g' to get this)
153+
141154
# Optional: Database (defaults to SQLite)
142155
DATABASE_URL=sqlite:///data/github_backup.db
143156
@@ -146,6 +159,33 @@ FLASK_ENV=production
146159
LOG_LEVEL=INFO
147160
```
148161

162+
#### Understanding PUID and PGID
163+
164+
The `PUID` (Process User ID) and `PGID` (Process Group ID) environment variables allow you to run the container with the same user and group IDs as your host system user. This ensures that:
165+
166+
- Files created by the container have the correct ownership
167+
- You can read/write the mounted volumes without permission issues
168+
- Backups are accessible from the host system
169+
170+
To find your IDs:
171+
```bash
172+
# Get your user ID
173+
id -u
174+
175+
# Get your group ID
176+
id -g
177+
178+
# Get both at once
179+
id
180+
```
181+
182+
**Example output:**
183+
```
184+
uid=1000(username) gid=1000(username) groups=1000(username),4(adm),24(cdrom)...
185+
```
186+
187+
In this case, set `PUID=1000` and `PGID=1000`.
188+
149189
### 5. First Time Setup
150190
151191
1. Access the web interface at `http://localhost:8080`

Dockerfile

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,54 @@
1-
FROM python:3.13-slim
1+
FROM python:3.11-slim
2+
3+
# Set environment variables to prevent interactive prompts and optimize Python
4+
ENV DEBIAN_FRONTEND=noninteractive \
5+
DEBCONF_NONINTERACTIVE_SEEN=true \
6+
PYTHONUNBUFFERED=1 \
7+
PYTHONDONTWRITEBYTECODE=1 \
8+
PIP_NO_CACHE_DIR=1 \
9+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
10+
PUID=1000 \
11+
PGID=1000
212

313
# Install system dependencies
4-
RUN apt-get update && apt-get install -y \
14+
RUN apt-get update && apt-get install -y --no-install-recommends \
515
git \
616
curl \
717
zip \
818
unzip \
919
cron \
10-
&& rm -rf /var/lib/apt/lists/*
20+
gosu \
21+
&& apt-get clean \
22+
&& rm -rf /var/lib/apt/lists/* \
23+
&& rm -rf /tmp/* \
24+
&& rm -rf /var/tmp/*
1125

1226
# Create app directory
1327
WORKDIR /app
1428

1529
# Copy requirements first for better caching
1630
COPY requirements.txt .
1731

18-
# Install Python dependencies
19-
RUN pip install --no-cache-dir -r requirements.txt
32+
# Install Python dependencies with optimizations
33+
RUN pip install --no-cache-dir --disable-pip-version-check --no-compile \
34+
-r requirements.txt \
35+
&& pip cache purge
2036

2137
# Copy application code
2238
COPY . .
2339

24-
# Create necessary directories
25-
RUN mkdir -p /app/backups /app/logs /app/data
40+
# Create necessary directories and set permissions in one layer
41+
RUN mkdir -p /app/backups /app/logs /app/data && \
42+
chmod +x start.sh && \
43+
chmod +x entrypoint.sh
2644

27-
# Set permissions
28-
RUN chmod +x start.sh
45+
# Create user with configurable UID/GID
46+
RUN groupadd -g ${PGID} appuser && \
47+
useradd -u ${PUID} -g ${PGID} -m -s /bin/bash appuser && \
48+
chown -R appuser:appuser /app
49+
50+
# Switch back to root for entrypoint (needed for user/group modifications)
51+
USER root
2952

3053
# Expose port
3154
EXPOSE 8080
@@ -34,5 +57,6 @@ EXPOSE 8080
3457
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
3558
CMD curl -f http://localhost:8080/health || exit 1
3659

37-
# Start the application
60+
# Set entrypoint and default command
61+
ENTRYPOINT ["/app/entrypoint.sh"]
3862
CMD ["./start.sh"]

Dockerfile.root

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
FROM python:3.11-slim
2+
3+
# Set environment variables to prevent interactive prompts and optimize Python
4+
ENV DEBIAN_FRONTEND=noninteractive \
5+
DEBCONF_NONINTERACTIVE_SEEN=true \
6+
PYTHONUNBUFFERED=1 \
7+
PYTHONDONTWRITEBYTECODE=1 \
8+
PIP_NO_CACHE_DIR=1 \
9+
PIP_DISABLE_PIP_VERSION_CHECK=1
10+
11+
# Install system dependencies
12+
RUN apt-get update && apt-get install -y --no-install-recommends \
13+
git \
14+
curl \
15+
zip \
16+
unzip \
17+
cron \
18+
&& apt-get clean \
19+
&& rm -rf /var/lib/apt/lists/* \
20+
&& rm -rf /tmp/* \
21+
&& rm -rf /var/tmp/*
22+
23+
# Create app directory
24+
WORKDIR /app
25+
26+
# Copy requirements first for better caching
27+
COPY requirements.txt .
28+
29+
# Install Python dependencies with optimizations
30+
RUN pip install --no-cache-dir --disable-pip-version-check --no-compile \
31+
-r requirements.txt \
32+
&& pip cache purge
33+
34+
# Copy application code
35+
COPY . .
36+
37+
# Create necessary directories and set permissions in one layer
38+
RUN mkdir -p /app/backups /app/logs /app/data && \
39+
chmod +x start.sh
40+
41+
# Expose port
42+
EXPOSE 8080
43+
44+
# Health check
45+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
46+
CMD curl -f http://localhost:8080/health || exit 1
47+
48+
# Start the application
49+
CMD ["./start.sh"]

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ services:
1313
environment:
1414
- SECRET_KEY=your-secret-key-change-this
1515
- DATABASE_URL=sqlite:///data/github_backup.db
16+
- PUID=1000 # Change to your user ID (run 'id -u' to get yours)
17+
- PGID=1000 # Change to your group ID (run 'id -g' to get yours)
1618
restart: unless-stopped
1719
healthcheck:
1820
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]

entrypoint.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
3+
# Get PUID and PGID from environment variables, with defaults
4+
PUID=${PUID:-1000}
5+
PGID=${PGID:-1000}
6+
7+
# Get current user info
8+
CURRENT_UID=$(id -u appuser)
9+
CURRENT_GID=$(id -g appuser)
10+
11+
# Only modify user/group if they're different from current
12+
if [ "$PUID" != "$CURRENT_UID" ] || [ "$PGID" != "$CURRENT_GID" ]; then
13+
echo "Updating user appuser to UID:$PUID and GID:$PGID"
14+
15+
# Update group ID if needed
16+
if [ "$PGID" != "$CURRENT_GID" ]; then
17+
groupmod -g "$PGID" appuser
18+
fi
19+
20+
# Update user ID if needed
21+
if [ "$PUID" != "$CURRENT_UID" ]; then
22+
usermod -u "$PUID" appuser
23+
fi
24+
25+
# Fix ownership of app directory
26+
chown -R appuser:appuser /app
27+
28+
# Fix ownership of mounted volumes if they exist
29+
[ -d /app/data ] && chown -R appuser:appuser /app/data
30+
[ -d /app/backups ] && chown -R appuser:appuser /app/backups
31+
[ -d /app/logs ] && chown -R appuser:appuser /app/logs
32+
fi
33+
34+
# Switch to appuser and execute the original command
35+
exec gosu appuser "$@"

start-root.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
3+
# Start cron daemon (requires root privileges)
4+
service cron start
5+
6+
# Initialize database if it doesn't exist
7+
python init_db.py
8+
9+
# Start the Flask application
10+
exec gunicorn --bind 0.0.0.0:8080 --workers 4 --timeout 120 app:app

start.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

3-
# Start cron daemon
4-
service cron start
3+
# Note: Running as non-root user, so we can't start system cron
4+
# Instead, we'll rely on APScheduler for job scheduling
55

66
# Initialize database if it doesn't exist
77
python init_db.py

0 commit comments

Comments
 (0)