1. Requirements
- PHP 7.4+ with SQLite3 (PDO) and cURL extensions
- Apache with
mod_rewriteenabled - Any standard shared hosting, VPS, or dedicated server
Optional for NFT storefront:
- Sui CLI for deploying the smart contract
- A Sui wallet (like Sui Wallet) for minting and managing NFTs
2. Installation
Clone the repo
git clone https://github.com/AleBlom/artistier.git
cd artistier
Directory structure
artistier/
├── config/ ← configuration
├── contract/ ← Sui Move smart contract
├── cron/ ← email drip cron script
├── logs/ ← log files (auto-created)
└── public/ ← web root
├── api/ ← JSON API endpoints
├── css/ ← stylesheets
├── db/ ← SQLite database + init script
├── js/ ← frontend scripts
└── img/ ← favicon + uploads
Option A: VPS / Dedicated Server
Point your Apache DocumentRoot to the public/ directory:
<VirtualHost *:80>
ServerName yourdomain.com
DocumentRoot /var/www/artistier/public
<Directory /var/www/artistier/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
With this setup, config/, cron/, and logs/ are outside the web root entirely — no web access possible.
Option B: Shared Hosting
On shared hosting you typically can't change the document root. Copy everything into your web root:
public_html/ ← your web root
├── config/ ← protected by .htaccess
├── cron/ ← protected by .htaccess
├── logs/ ← protected by .htaccess
├── .htaccess
├── bootstrap.php
├── index.php
├── api/
├── css/
├── db/
├── js/
└── img/
bootstrap.php auto-detects which layout you're using — no path editing needed. Sensitive directories are protected by both their own .htaccess deny rules and rewrite rules in the main .htaccess, so your API keys and config files are never web-accessible even though they're inside the web root.
Copy config files
cp config/site.example.php config/site.php
cp config/email.example.php config/email.php
cp config/nft.example.php config/nft.php
cp config/homepage.example.php config/homepage.php
Add your profile picture
Place a square image at public/img/pfp.jpg (or public_html/img/pfp.jpg on shared hosting).
Add favicon files
Replace the files in public/img/:
favicon.icofavicon-32x32.pngapple-touch-icon.png(180x180)android-chrome-192x192.png
3. Configuration
All configuration lives in four PHP files using define() constants.
config/site.php
Core site identity and social links.
| Constant | Description |
|---|---|
SITE_NAME | Your display name |
SITE_TAGLINE | Short intro shown on homepage |
SITE_DOMAIN | Your domain (shown in footer) |
SITE_LEGAL_ENTITY | Company name for privacy policy |
SITE_LEGAL_ADDRESS | Address for privacy policy |
SITE_CONTACT_EMAIL | Contact email for privacy policy |
TEST_EMAIL | Email address for admin preview sends |
SOCIAL_* | Social links (Instagram, TikTok, X, LinkedIn, YouTube). Leave empty to hide. |
config/email.php
ElasticEmail API credentials for the newsletter.
| Constant | Description |
|---|---|
EMAIL_API_KEY | Your ElasticEmail API key |
EMAIL_FROM | Sender email address |
EMAIL_FROM_NAME | Sender display name |
SITE_URL | Full URL with https (for unsubscribe links) |
config/nft.php
Sui blockchain and Walrus storage settings. Leave defaults until you deploy the contract.
| Constant | Description |
|---|---|
SUI_NETWORK | testnet or mainnet |
SUI_RPC_URL | Sui fullnode RPC endpoint |
SUI_PACKAGE_ID | Deployed contract package ID |
SUI_MARKETPLACE_ID | Shared Marketplace object ID |
SUI_ADMIN_ADDRESS | Admin wallet address |
SUI_ADMIN_CAP_ID | AdminCap object ID |
WALRUS_PUBLISHER_URL | Walrus publisher for uploads |
WALRUS_AGGREGATOR_URL | Walrus aggregator for serving images |
WALRUS_EPOCHS | Storage duration in epochs |
STOREFRONT_* | Name, description, and artist for the storefront |
config/homepage.php
Optional HTML sections appended to the homepage between the Art section and the Blog. Use this for commissions, exhibitions, project links, or anything else. See the example file for the card format.
4. Database
The database is a single SQLite file at db/blog.db. Initialize it by running:
php public/db/init.php # Option A (VPS)
php db/init.php # Option B (shared hosting)
This creates the tables:
| Table | Purpose |
|---|---|
posts | Blog posts (slug, title, content, timestamps) |
settings | Key-value store (admin password hash) |
subscribers | Newsletter subscribers with status and drip position |
email_sequence | Drip email content (subject, HTML body, text body) |
collections | NFT collections with cover images and metadata |
nfts | Individual NFTs with pricing, status, and Sui object IDs |
nft_config | Runtime NFT configuration |
changeme. Log in and change it immediately.
The .htaccess blocks direct access to .db files, but placing the database outside the web root is even safer if your hosting allows it.
5. NFT Storefront Setup
The NFT storefront is optional. Skip this section if you only need blog + newsletter.
Deploy the smart contract
Install the Sui CLI, then:
cd contract
sui client publish --gas-budget 100000000
The output contains the IDs you need. Look for:
- Package ID — the published package object
- Marketplace — the shared object created by
init() - AdminCap — the admin capability object sent to your wallet
Copy these into config/nft.php.
Walrus image storage
NFT images are uploaded to Walrus decentralized storage from the admin dashboard. The default config points to testnet. For mainnet:
define('WALRUS_PUBLISHER_URL', 'https://publisher.walrus.space');
define('WALRUS_AGGREGATOR_URL', 'https://aggregator.walrus.space');
Wallet connection
Buyers connect their Sui wallet (browser extension) to purchase NFTs with USDC. The storefront handles wallet detection, transaction building, and purchase confirmation automatically.
Going to mainnet
- Redeploy the contract on mainnet:
sui client switch --env mainnet - Update
SUI_NETWORKtomainnetinconfig/nft.php - Update
SUI_RPC_URLto the mainnet endpoint - Update Walrus URLs to mainnet endpoints
- Update the contract IDs with the new mainnet values
6. Newsletter & Cron
ElasticEmail setup
- Sign up at elasticemail.com
- Get your API key from Settings → API
- Verify your sender domain
- Add your API key and sender info to
config/email.php
Cron job
The drip sequence sends one email per subscriber per day. Set up a daily cron:
# Run at 9 AM daily
0 9 * * * php /path/to/cron/email-sequence.php
On shared hosting, use your host's cron job manager (cPanel → Cron Jobs).
How the drip works
- New subscriber signs up → status
pending, sequence position0 - Subscriber confirms via email link → status
active - Cron runs daily → sends the email at the subscriber's current position
- After sending, position advances by 1
- When position exceeds the last email, nothing more is sent
Email template
The email wrapper template is at cron/email-template.php. Edit it to match your branding.
7. Admin Dashboard
Access the admin at /admin after logging in on the homepage.
The admin has four tabs:
- Email Sequence — Create and reorder drip emails. Preview renders. Send test emails to your address.
- Subscribers — View all subscribers, their status, and drip position.
- Collections — Create NFT collections with cover images (uploaded to Walrus), descriptions, and royalty settings.
- NFTs — Add NFTs to collections with images, pricing, and edition info. Mint and list on Sui from the dashboard.
8. Customization
Homepage sections
Edit config/homepage.php to add custom sections between the Art grid and the Blog. Use the card format from the example file:
<section class="section">
<h2 class="section-title">Commissions</h2>
<div class="projects-grid">
<a href="/art" class="project-card">
<div class="project-logo" style="...">...</div>
<div>
<h3>Custom Portraits</h3>
<p>Starting at $200.</p>
</div>
</a>
</div>
</section>
CSS
All styles are in css/style.css (public site) and css/admin.css (admin dashboard). The design uses CSS custom properties where applicable.
Favicon
Replace the files in img/. The HTML references favicon.ico, favicon-32x32.png, apple-touch-icon.png, and android-chrome-192x192.png.
Blog post images
Posts support image uploads via the post editor. Images are stored in img/uploads/.
9. Security
Artistier uses layered protection for sensitive files, especially important on shared hosting where config/ (containing API keys) is inside the web root.
Directory protection
| Directory | Contains | Protection |
|---|---|---|
config/ | API keys, secrets, site settings | .htaccess deny + rewrite rule |
cron/ | Email sending scripts | .htaccess deny + rewrite rule |
logs/ | Log files | .htaccess deny + rewrite rule |
db/ | SQLite database | .htaccess deny + <Files> rule |
Each sensitive directory has its own .htaccess with Require all denied. The main .htaccess also has rewrite rules blocking /config/, /cron/, and /logs/ as a second layer.
config/, cron/, and logs/ are outside the web root entirely, so they're never web-accessible regardless of .htaccess rules.
Admin authentication
Passwords are hashed with PHP's password_hash() (bcrypt). Sessions are server-side. The default password is changeme — change it immediately after first login.
Recommendations
- Change the default admin password before doing anything else
- Use HTTPS (most shared hosts provide free SSL via Let's Encrypt)
- Keep your
config/*.phpfiles out of version control (they're in.gitignore) - If your host supports it, prefer Option A (VPS) to keep secrets outside the web root
10. FAQ
Do I need the NFT storefront?
No. The blog and newsletter work independently. Leave config/nft.php with empty IDs and the art sections won't appear.
Can I use a different email provider?
The cron script sends via a simple HTTP POST to ElasticEmail's API. You could swap it for any transactional email API (SendGrid, Mailgun, etc.) by editing cron/email-sequence.php and the subscribe/confirm endpoints in api/.
Is the admin password secure?
Passwords are hashed with PHP's password_hash() (bcrypt). The default is changeme — change it after first login. Sessions are server-side.
Can I run this on Nginx?
Yes, but you'll need to convert the .htaccess rewrite rules to Nginx config. The key rules route /post/slug, /art/collection/piece, /admin, and a few other clean URLs to their PHP files.
How do I back up?
Copy db/blog.db and img/uploads/. That's everything. Config files don't change at runtime.
Where are the logs?
Email sequence logs go to logs/email-sequence.log and logs/email-sequence-error.log. The logs/ directory is created automatically.