Self-hosted social platform built with Node.js, Express and TypeScript
4.6K
A modern self-hosted social media platform built with Node.js, Express, TypeScript, MySQL, and Redis. Features posts with optional images, comments, likes/dislikes, email verification, and a guided setup wizard.
GitHub: https://github.com/omairsalman03/UsersConnectā
Live Version: https://usersconnect.cloudomair.org/ā
UPDATE_CHECK_ENABLED=falseamd64 and arm64 (Raspberry Pi, ARM NAS, Apple Silicon)As of v1.1.0, authentication cookies are always set with the Secure attribute (required by SameSite=None), so the app must be served over HTTPS for sign-in to work.
http://localhost is treated as secure by Chrome/Firefox (so it works), but accessing from a phone over the LAN requires real TLS (e.g. mkcert or a tunnel). See "Why HTTPS is required"ā in the README.docker pull omairsalman/usersconnect:latest
Save as docker-compose.yml:
services:
app:
image: omairsalman/usersconnect:latest
ports:
- "3000:3000"
volumes:
- ./config.yaml:/app/config.yaml
- ./logs:/app/logs
environment:
- NODE_ENV=production
- DATABASE_HOST=mysql
- DATABASE_USERNAME=root
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- DATABASE_NAME=usersconnect
- REDIS_HOST=redis
- REDIS_PASSWORD=${REDIS_PASSWORD}
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
depends_on:
- mysql
- redis
restart: unless-stopped
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}
MYSQL_DATABASE: usersconnect
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
mysql_data:
redis_data:
docker-compose up -d
Generate secrets for .env:
openssl rand -base64 16 # For passwords
openssl rand -base64 32 # For JWT secrets
/setup)Done! Your instance is ready to use.
Note: Because authentication requires HTTPS, access your instance through your HTTPS reverse proxy rather than plain
http://...:3000. See the HTTPS note above.
docker run -d \
-p 3000:3000 \
-v $(pwd)/config.yaml:/app/config.yaml \
-v $(pwd)/logs:/app/logs \
-e NODE_ENV=production \
-e DATABASE_HOST=your-mysql-host \
-e DATABASE_USERNAME=root \
-e DATABASE_PASSWORD=yourpassword \
-e DATABASE_NAME=usersconnect \
-e REDIS_HOST=your-redis-host \
-e REDIS_PASSWORD=yourredispassword \
-e ACCESS_TOKEN_SECRET=$(openssl rand -base64 32) \
-e REFRESH_TOKEN_SECRET=$(openssl rand -base64 32) \
omairsalman/usersconnect:latest
Add these environment variables:
-e S3_ACCESS_KEY=your-aws-access-key \
-e S3_SECRET_KEY=your-aws-secret-key \
-e S3_BUCKET_NAME=usersconnect-media \
-e S3_REGION=us-east-1 \
-e SMTP_HOST=smtp.zoho.com \
-e SMTP_PORT=465 \
-e SMTP_SECURE=true \
-e [email protected] \
-e SMTP_PASSWORD=your_smtp_password \
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
DATABASE_HOST | database.host | MySQL host | mysql or localhost |
DATABASE_PORT | database.port | MySQL port (optional) | 3306 (default) |
DATABASE_USERNAME | database.username | MySQL user | root |
DATABASE_PASSWORD | database.password | MySQL password | yourpassword |
DATABASE_NAME | database.name | Database name | usersconnect |
REDIS_HOST | redis.host | Redis host | redis or localhost |
REDIS_PORT | redis.port | Redis port (optional) | 6379 (default) |
REDIS_PASSWORD | redis.password | Redis password (optional) | yourredispassword |
ACCESS_TOKEN_SECRET | jwt.accessTokenSecret | JWT access token secret | Generate: openssl rand -base64 32 |
REFRESH_TOKEN_SECRET | jwt.refreshTokenSecret | JWT refresh token secret | Generate: openssl rand -base64 32 |
Image uploads are automatically enabled when these variables are set:
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
S3_ACCESS_KEY | s3.accessKey | S3 access key ID | AKIAIOSFODNN7EXAMPLE |
S3_SECRET_KEY | s3.secretKey | S3 secret access key | wJalrXUtnFEMI/... |
S3_BUCKET_NAME | s3.bucketName | S3 bucket name | usersconnect-media |
S3_REGION | s3.region | AWS region | us-east-1 |
S3_ENDPOINT | s3.endpoint | Custom endpoint (for non-AWS S3) | https://s3.example.com |
Email features are automatically enabled when these variables are set:
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
SMTP_HOST | smtp.host | SMTP server host | smtp.zoho.com |
SMTP_PORT | smtp.port | SMTP server port | 465 or 587 |
SMTP_SECURE | smtp.secure | Use SSL/TLS | true or false |
SMTP_USER | smtp.user | SMTP username | [email protected] |
SMTP_PASSWORD | smtp.password | SMTP password | your_smtp_password |
CORS is disabled by default. Enable for separate frontend applications:
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
CORS_ENABLED | cors.enabled | Enable CORS | true or false |
CORS_ALLOWED_ORIGINS | cors.allowedOrigins | Allowed origins (comma-separated) | http://localhost:4200,https://app.example.com |
CORS_ALLOW_CREDENTIALS | cors.allowCredentials | Allow credentials | true or false |
CORS_ALLOWED_METHODS | cors.allowedMethods | Allowed HTTP methods (comma-separated) | GET,POST,PUT,DELETE |
CORS_ALLOWED_HEADERS | cors.allowedHeaders | Allowed headers (comma-separated) | Content-Type,Authorization |
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
LOG_LEVEL | logging.level | Winston log level | info, debug, warn, error |
Logging file location and rotation are configurable via
logging.directory,logging.maxFileSize, andlogging.maxFilesinconfig.yaml. A relativedirectory(the default,logs) resolves under the app working directory (/app/logsin the container); an absolute path is honored as-is.
Enabled by default. Once a day, sends only the product name and running version.
| Environment Variable | YAML Equivalent | Description | Example |
|---|---|---|---|
UPDATE_CHECK_ENABLED | updateCheck.enabled | Turn the daily update check on or off | true or false |
Configuration Priority: Environment variables always override YAML:
Defaults ā config.yaml ā Environment Variables
Option 1: config.yaml Only (All Configuration)
# config.yaml - Complete example with all options
# Required: Database
database:
host: mysql
port: 3306
username: root
password: yourpassword
name: usersconnect
# Required: Redis
redis:
host: redis
port: 6379
password: yourredispassword # Optional
# Required: JWT
jwt:
accessTokenSecret: your-access-token-secret-here
refreshTokenSecret: your-refresh-token-secret-here
# Optional: S3 Image Uploads (remove if not using)
s3:
accessKey: AKIAIOSFODNN7EXAMPLE
secretKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
bucketName: usersconnect-media
region: us-east-1
endpoint: https://s3.example.com # Only for non-AWS S3
# Optional: SMTP Email (remove if not using)
smtp:
host: smtp.zoho.com
port: 465
secure: true
user: [email protected]
password: your_smtp_password
# Optional: CORS (remove if not using)
cors:
enabled: true
allowedOrigins:
- http://localhost:4200
- https://app.example.com
allowCredentials: true
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowedHeaders:
- Content-Type
- Authorization
# Optional: Logging
logging:
level: info # debug, info, warn, error
# Optional: Update check (enabled by default)
updateCheck:
enabled: true
Option 2: Environment Variables Only
environment:
# Required
- NODE_ENV=production
- DATABASE_HOST=mysql
- DATABASE_PORT=3306
- DATABASE_USERNAME=root
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- DATABASE_NAME=usersconnect
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD}
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
# Optional: S3
- S3_ACCESS_KEY=AKIA...
- S3_SECRET_KEY=${S3_SECRET_KEY}
- S3_BUCKET_NAME=usersconnect-media
- S3_REGION=us-east-1
- S3_ENDPOINT=https://s3.example.com
# Optional: SMTP
- SMTP_HOST=smtp.zoho.com
- SMTP_PORT=465
- SMTP_SECURE=true
- [email protected]
- SMTP_PASSWORD=${SMTP_PASSWORD}
# Optional: CORS
- CORS_ENABLED=true
- CORS_ALLOWED_ORIGINS=http://localhost:4200
- CORS_ALLOW_CREDENTIALS=true
- CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE
- CORS_ALLOWED_HEADERS=Content-Type,Authorization
# Optional: Logging
- LOG_LEVEL=info
# Optional: Update check (enabled by default)
- UPDATE_CHECK_ENABLED=true
Option 3: Mixed (Secrets in ENV, Config in YAML)
# docker-compose.yml
volumes:
- ./config.yaml:/app/config.yaml
environment:
# Secrets only
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- REDIS_PASSWORD=${REDIS_PASSWORD}
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
- S3_SECRET_KEY=${S3_SECRET_KEY}
- SMTP_PASSWORD=${SMTP_PASSWORD}
# config.yaml
database:
host: mysql
port: 3306
username: root
name: usersconnect
redis:
host: redis
port: 6379
s3:
accessKey: AKIA...
bucketName: usersconnect-media
region: us-east-1
endpoint: https://s3.example.com
smtp:
host: smtp.zoho.com
port: 465
secure: true
user: [email protected]
cors:
enabled: true
allowedOrigins:
- http://localhost:4200
- https://app.example.com
allowCredentials: true
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowedHeaders:
- Content-Type
- Authorization
logging:
level: info
Works with any S3-compatible storage:
ā ļø The MinIO example has been removed. MinIO withdrew its community edition images from both Docker Hub and quay.io in September 2026, so they can no longer be pulled. A tested, maintained self-hosted alternative will be documented in an upcoming release. Until then, use any S3-compatible provider from the list above. Existing MinIO setups keep running from Docker's local cache, so avoid re-pulling the MinIO image.
When SMTP is configured:
When SMTP is not configured:
Secure/SameSite=None, so the app must be served over HTTPS via a reverse proxy (Nginx/Caddy/Traefik/Nginx Proxy Manager)cors.allowedOriginsopenssl rand -base64 32Minimum:
amd64 or arm64 host (arm64 images from v1.2.0)Recommended:
The Docker image bundles its own Node.js runtime; a local Node.js install is only needed when building from source.
Secure and browsers reject them over plain HTTPhttp://localhost is treated as secure by Chrome/Firefox; LAN-IP access from a phone needs real TLS)allowCredentials: true and your origin is in allowedOriginscors.allowedOriginsDATABASE_HOST matches your setupREDIS_HOST is correctREDIS_PASSWORD if setUPDATE_CHECK_ENABLED=falselatest - Latest stable release1.2.0 - Current release (amd64 and arm64)1.1.0, 1.0.4, 1.0.3, 1.0.2, 1.0.1, 1.0.0 - Previous releases (amd64 only)Pull a specific version:
docker pull omairsalman/usersconnect:1.2.0
# Backup database first
docker exec mysql mysqldump -u root -p usersconnect > backup.sql
# Pull the new image
docker pull omairsalman/usersconnect:latest
# Recreate containers (migrations run automatically)
docker-compose down
docker-compose up -d
# Verify in logs
docker-compose logs app
No database changes in v1.2.0. HTTPS is still required for authentication (since v1.1.0). If you use a separate frontend on another origin, make sure it's listed in cors.allowedOrigins; see Troubleshooting.
git clone https://github.com/omairsalman03/UsersConnect.git
cd UsersConnect
git checkout v1.2.0
npm install
npm run build
docker build -t usersconnect:custom .
| Tags | License |
|---|---|
1.2.0 and later | AGPL-3.0-onlyā |
1.1.0 and earlier, including 1.0.x, the 1.0.0-rc tags, v0.1 and v0.2 | MITā |
latest is licensed according to the version it points to. See LICENSING.mdā .
Omair Salman
Initially developed during summer field training at AsalTechā , with continued development thereafter.
ā Star on GitHub: https://github.com/omairsalman03/UsersConnectā
š¬ Discussions: https://github.com/omairsalman03/UsersConnect/discussionsā
š Report Issues: https://github.com/omairsalman03/UsersConnect/issuesā
Latest Release: v1.2.0 š
Content type
Image
Digest
sha256:52b349f58ā¦
Size
113.8 MB
Last updated
about 1 month ago
docker pull omairsalman/usersconnect