Password-protected web gallery with client-side encryption. All folders and files are encrypted with AES-256 using your password — only users with the correct password can access and view the content.
- Password-protected access to the gallery
- All folders and files are encrypted with your password
- Files are decrypted on-the-fly when viewed
- Automatic thumbnail generation for images and videos
- Fast gallery browsing with thumbnail previews
- Create new folders with encrypted names
- Upload images and videos (multi-file with drag-and-drop), up to 2 GB per file by default (configurable)
- Support for video formats: MP4, MOV, AVI, MKV, WebM, 3GP, FLV, WMV, M4V
- Support for image formats: JPEG, PNG, GIF, WebP
- Built-in video player
- HTTPS support: self-signed certificates or automatic TLS via Let's Encrypt (ACME)
- No server-side password storage
-
Download the latest release archive for your platform from the Releases page:
go_gal_linux_amd64.tar.gz— Linux x86-64go_gal_linux_arm64.tar.gz— Linux ARM64 (Raspberry Pi, etc.)go_gal_darwin_amd64.tar.gz— macOS Intelgo_gal_darwin_arm64.tar.gz— macOS Apple Silicon
-
Extract the archive:
mkdir go_gal && tar -xzvf go_gal_linux_amd64.tar.gz -C go_gal cd go_gal
-
Run the installation script:
sudo ./install.sh
The script is interactive and will ask you:
- Session key and salt for encryption (press Enter to generate random values)
- Host and port to bind to
- SSL/TLS mode: HTTP only, manual certificates, or automatic Let's Encrypt
It creates a
gogalsystem user, installs everything to/opt/go_gal, and registers a systemd service. You can retrieve the generated keys any time with:sudo grep -E "GO_GAL_(SESSION_KEY|SALT)" /etc/systemd/system/go_gal.service -
Start and enable the service:
sudo systemctl start go_gal sudo systemctl enable go_gal -
Open
http://<your-server>:8080in a browser and set your gallery password.
-
Download
go_gal_windows_amd64.zipfrom the Releases page. -
Extract the archive to a folder, e.g.
C:\go_gal\. -
Open PowerShell and run the application:
cd C:\go_gal .\go_gal.exe --host=0.0.0.0 --port=8080
-
Open
http://localhost:8080in a browser.
Use NSSM to install go_gal as a background service:
nssm install go_gal "C:\go_gal\go_gal.exe"
# In the NSSM GUI set the working directory to C:\go_gal
nssm start go_galSet these before starting the application (recommended for production):
$env:GO_GAL_SESSION_KEY = "your-random-secure-key"
$env:GO_GAL_SALT = "your-random-secure-salt"
.\go_gal.exe --host=0.0.0.0 --port=8080For video thumbnail generation, install FFmpeg:
- macOS:
brew install ffmpeg - Ubuntu/Debian:
sudo apt install ffmpeg - Windows: Download from ffmpeg.org and add to PATH
Image thumbnails work without FFmpeg. Video files can still be uploaded and viewed — placeholder images will be shown instead of actual video thumbnails.
Video thumbnails are created at upload time from the frame at 1 second (or the first frame for shorter clips). Videos uploaded before FFmpeg was installed keep their placeholder; re-upload them to get a real thumbnail.
- File size: 2 GB per file by default. Change it with
--max-upload-mb, e.g.--max-upload-mb=4096for 4 GB. Oversized files are rejected in the browser before sending; the server also enforces the limit and returns413. - Time: each upload must finish within 30 minutes. On slow connections this caps the practical file size (about 2 GB at 10 Mbit/s).
- Disk space: an upload temporarily needs about 3× the file size (upload buffer + encrypted copy + a temp copy for video thumbnails).
- Reverse proxy: if go_gal runs behind nginx, raise its limit too — nginx rejects bodies over 1 MB by default:
client_max_body_size 2048m;
- Long filenames are shortened to fit the 255-byte filesystem limit after encryption: names over 96 bytes (about 48 Cyrillic or 96 Latin characters) are trimmed and get a short hash suffix, keeping the extension.
To change the limit for the systemd service, add the flag to ExecStart in /etc/systemd/system/go_gal.service:
ExecStart=/opt/go_gal/go_gal --port=${PORT} --host=${HOST} $SSL_OPTS --max-upload-mb=4096
Then apply it with sudo systemctl daemon-reload && sudo systemctl restart go_gal. update.sh keeps this line; re-running install.sh resets it.
The installation includes an update.sh script that handles updates automatically:
sudo /opt/go_gal/update.shThe script will:
- Check for the latest version on GitHub
- Backup your current installation
- Preserve your encryption keys
- Download and install the update
- Restart the service
Options:
sudo /opt/go_gal/update.sh --version=v0.0.26 # Update to specific version
sudo /opt/go_gal/update.sh --dry-run # Check for updates without installing-
Backup your encryption keys:
sudo grep -E "GO_GAL_(SESSION_KEY|SALT)" /etc/systemd/system/go_gal.serviceNote down the values for
GO_GAL_SESSION_KEYandGO_GAL_SALT. -
Stop the service:
sudo systemctl stop go_gal
-
Download the new version from the Releases page and extract.
-
Run the installer and enter your existing session key and salt when prompted:
sudo ./install.sh
-
Start the service:
sudo systemctl start go_gal
Important: Always preserve your session key and salt — new random values will make your encrypted data inaccessible.
The distribution includes an update.ps1 script:
.\update.ps1The script will:
- Check for the latest version on GitHub
- Backup your current installation
- Preserve your encryption keys (from .env file or environment variables)
- Download and install the update
Options:
.\update.ps1 -Version v0.0.26 # Update to specific version
.\update.ps1 -DryRun # Check for updates without installingNote: For the update script to work, create a .env file in the installation directory with your keys:
GO_GAL_SESSION_KEY=your-key
GO_GAL_SALT=your-salt- Stop the application (Ctrl+C or
nssm stop go_gal) - Download the new version and extract
- Start the application with the same environment variables
sudo /opt/go_gal/uninstall.shThis will stop and disable the service, remove the service file, and remove the installation directory.
Delete the application folder and remove the NSSM service if configured:
nssm remove go_gal confirmThis section only applies if you are upgrading from a version older than 0.0.22. If you are installing fresh or upgrading from 0.0.22 or later, you can skip this section.
Old versions used v1 encryption format (SHA-256 key derivation). New versions use v2 format (Argon2id). The new binary can read old v1 files without migration, but migration is strongly recommended for security.
| Before (v1) | After (v2) | |
|---|---|---|
| Key derivation | SHA-256 (single pass) | Argon2id (GPU-resistant) |
| Filename encryption | AES-256-CFB | AES-256-GCM |
| File HMAC | Covers ciphertext only | Covers IV + ciphertext |
The gallery password does not change. All your files remain accessible.
cp -r gallery/ gallery_backup/
cp -r thumbnails/ thumbnails_backup/sudo systemctl stop go_gal # or kill the processMake sure you use the same GO_GAL_SALT value as your running instance:
export GO_GAL_SALT="your-salt"
./go_gal --migrateYou will be prompted for the gallery password.
Example output:
Enter gallery password:
Starting migration...
Migrated: gallery/3a8f1c...enc
Migrated: gallery/7d2b04...enc
...
=== Migration Complete ===
Files processed: 47
Files migrated: 47
Files skipped: 0 (already v2)
File errors: 0
Dirs migrated: 3
Dir errors: 0
If there are any errors, the original files are untouched — restore from backup and report the issue.
sudo systemctl start go_galOn first login after migration you will notice a ~1 second delay at the login screen — this is Argon2id computing the key, which prevents brute-force attacks.
rm -rf gallery_backup/ thumbnails_backup/Requires Go 1.23+:
git clone https://github.com/rhamdeew/go_gal.git
cd go_gal
go mod download
go build -o go_gal ../go_galCommand line arguments:
--host=<ip> Host IP address to bind to (default: localhost)
--port=<number> Port number (default: 8080)
--ssl Enable HTTPS with self-signed certificates
--cert=<path> Path to SSL certificate file (default: cert.pem)
--key=<path> Path to SSL private key file (default: key.pem)
--acme Enable automatic HTTPS via Let's Encrypt
--acme-domain=<host> Domain name for the Let's Encrypt certificate (required with --acme)
--acme-email=<email> Email address for Let's Encrypt notifications
--acme-cache=<dir> Directory to cache Let's Encrypt certificates (default: acme-cache)
--max-upload-mb=<n> Maximum size of a single uploaded file in MB (default: 2048)
--migrate Migrate gallery files from v1 to v2 encryption format
--version Show version information
make build # Build the binary
make run # Build and run on http://localhost:8080
make run-ssl # Build and run with HTTPS on port 8443
make test # Run all tests
make test-coverage # Run tests and open the coverage report
make reset # Stop go_gal and delete local gallery/ and thumbnails/ (asks for confirmation)
make deps # Download Go module dependencies
make clean # Remove the binarymake reset is for local development: it permanently deletes every uploaded file and thumbnail.
# Run all tests
go test -v ./...
# Run tests with coverage
go test -cover ./...
# Run benchmarks
go test -bench=. -benchmemGO_GAL_SESSION_KEY: Custom session key for cookie encryption (default: hardcoded value)GO_GAL_SALT: Custom salt for password hashing (default: hardcoded value)GO_GAL_SSL_ENABLED: Set to "true" to enable HTTPS features
For production use, set custom values:
export GO_GAL_SESSION_KEY="your-random-secure-key"
export GO_GAL_SALT="your-random-secure-salt"
./go_gal --ssl=true- Folder and file names are encrypted using AES-256-GCM (authenticated encryption)
- File contents are encrypted with AES-256-CFB with HMAC-SHA256 integrity protection
- Password-based key derivation using Argon2id (GPU/ASIC-resistant, OWASP recommended)
- No passwords are stored on the server — only the derived key is held in the session
- Session-based authentication with secure cookies (HttpOnly, SameSite)
- Login rate limiting: 10 attempts per 15-minute window per IP
- Optional HTTPS with TLS 1.2+ — self-signed certificates or automatic Let's Encrypt via ACME
- Security response headers:
X-Frame-Options,X-Content-Type-Options,Content-Security-Policy,Referrer-Policy,Strict-Transport-Security - Protection against directory traversal attacks
| Version | KDF | File cipher | Filename cipher | Notes |
|---|---|---|---|---|
| v1 (legacy) | SHA-256 | AES-256-CFB + HMAC | AES-256-CFB | Readable by new binary |
| v2 (current) | Argon2id | AES-256-CFB + HMAC(IV+data) | AES-256-GCM | Written by new binary |
New files are always written in v2. Old v1 files remain readable until you run the migration.
This project uses GitHub Actions to automatically build and release binaries for multiple platforms when you create a new tag:
- Build binaries for Linux (amd64, arm64), Windows (amd64), macOS (amd64, arm64)
- Run tests
- Create a release with all binaries bundled
To create a new release:
git tag v1.0.0
git push origin v1.0.0This project is licensed under the MIT License - see the LICENSE file for details.
