Category Archives: Server

Как сделать виртуальные хосты на Апачи

Допустим, я жадный и хочу иметь два сайта, где на каждом стоит отдельный ВордПресс: Мой секси сайт и Мой эротик сайт. Я пошел и сделал для каждого сайта два разных домена: moisexysaite.duckdns.org и moieroticsaite.duckdns.org. Как их подключить на один и тот же Апачи на одном и том же компе?

Очень просто. Для этого надо сделать два виртуальных хоста.

pdf-icon Tutorial: Virtual_Hosts

1. Сначала сделаем отдельную папку для каждого из сайтов по имени домена:

sudo mkdir /var/www/moisexysaite.duckdns.org
sudo mkdir /var/www/moieroticsaite.duckdns.org

2. Внутри каждой папки сделаем еще одну папку html:

sudo mkdir /var/www/moisexysaite.duckdns.org/html
sudo mkdir /var/www/moieroticsaite.duckdns.org/html

3. Поставим для папок правильную принадлежность

sudo chown -R $USER:$USER /var/www/moisexysaite.duckdns.org/html
sudo chown -R $USER:$USER /var/www/moieroticsaite.duckdns.org/html

и разрешение.

sudo chmod -R 755 /var/www

4. Создадим конфигурационные файлы для каждого сайта.

Образец такого файла находится в /etc/apache2/sites-available/000-default.conf

sudo leafpad /etc/apache2/sites-available/moisexysaite.duckdns.org.conf
sudo leafpad /etc/apache2/sites-available/moieroticsaite.duckdns.org.conf

5. Скопируем в .conf файлы слдуещее:

a. Для moisexysaite.duckdns.org

<VirtualHost *:80>
ServerAdmin admin@moisexysaite.duckdns.org
ServerName moisexysaite.duckdns.org
ServerAlias www.moisexysaite.duckdns.org
DocumentRoot /var/www/moisexysaite.duckdns.org/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#RedirectMatch ^/$ /wordpress/
</VirtualHost>

b. Для moieroticsaite.duckdns.org

<VirtualHost *:80>
ServerAdmin admin@moieroticsaite.duckdns.org
ServerName moieroticsaite.duckdns.org
ServerAlias www.moieroticsaite.duckdns.org
DocumentRoot /var/www/moieroticsaite.duckdns.org/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#RedirectMatch ^/$ /wordpress/
</VirtualHost>

 

Note:
Примечательна строчка #RedirectMatch ^/$ /wordpress/. Она сейчас закоментирована.

Я полагаю, что на каждом сайте может стоять не один ВордПресс, а два, пять, сто – каждый в своей отдельной папке: wordpress1, wordpress5, wordpress100. Тогда, если вы хотите, чтоб Апачи при получении доменного имени, интернет адреса – moisexysaite.duckdns.org – показывал не просто содержимое html, корневой директории сайта:

virthost1

а сразу переключался на нужный вордпресс – wordpress1, например, то эту строчку надо раскомментировать и изменить так, чтоб она стала:

RedirectMatch ^/$ /wordpress1/

6. Включаем виртуальные хосты, которые мы только что сделали.

sudo a2ensite moisexysaite.duckdns.org
sudo a2ensite moieroticsaite.duckdns.org

Note:
Выключаются виртуальные хосты так:

sudo a2dissite moisexysaite.duckdns.org
sudo a2dissite moieroticsaite.duckdns.org

 

7. Перезагружаем Апачи.

sudo service apache2 restart

Setup FTP server on ubuntu 14.04

FTP is used to transfer files from one host to another over TCP network. This article explains how to setup FTP server on ubuntu 14.04 .

There are 3 popular FTP server packages available PureFTPD, VsFTPD and ProFTPD. Here i’ve used VsFTPD which is lightweight and less Vulnerability.

Setup FTP server on Ubuntu 14.04

Step 1 » Update repositories .

krizna@leela:~$ sudo apt-get update

Step 2 » Install VsFTPD package using the below command.

krizna@leela:~$ sudo apt-get install vsftpd

Step 3 » After installation open /etc/vsftpd.conf file and make changes as follows.
Uncomment the below lines (line no:29 and 33).

write_enable=YES
local_umask=022

» Uncomment the below line (line no: 120 ) to prevent access to the other folders outside the Home directory.

chroot_local_user=YES

and add the following line at the end.

allow_writeable_chroot=YES

» Add the following lines to enable passive mode.

pasv_enable=Yes
pasv_min_port=40000
pasv_max_port=40100

Step 4 » Restart vsftpd service using the below command.

krizna@leela:~$ sudo service vsftpd restart

Step 5 » Now ftp server will listen on port 21. Create user with the below command.Use /usr/sbin/nologin shell to prevent access to the bash shell for the ftp users .

krizna@leela:~$ sudo useradd -m john -s /usr/sbin/nologin
krizna@leela:~$ sudo passwd john

Step 6 » Allow login access for nologin shell . Open /etc/shells and add the following line at the end.

/usr/sbin/nologin

Now try to connect this ftp server with the username on port 21 using winscp or filezilla client and make sure that user cannot access the other folders outside the home directory.

setup-FTP-server-ubuntu-14-04-1

Please note using ftp on port 21 is a big security risk . it’s highly recommended to use SFTP. Please continue for SFTP configuration

Secure FTP ( SFTP )

SFTP is called as “Secure FTP” which generally use SSH File Transfer Protocol . so we need openssh-server package installed , Issue the below command if it’s not already installed.

krizna@leela:~$ sudo apt-get install openssh-server

Step 7 » Create a new group ftpaccess for FTP users.

krizna@leela:~$ sudo groupadd ftpaccess

Step 8 » Now make changes in this /etc/ssh/sshd_config file.
» Find and comment the below line

Subsystem sftp /usr/lib/openssh/sftp-server

and Add these lines at the end of the file.

Subsystem sftp internal-sftp
Match group ftpaccess
ChrootDirectory %h
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp

Step 9 » Restart sshd service.

krizna@leela:~$ sudo service ssh restart

Step 10 » The below steps must be followed while creating Users for sftp access.
Create user john with ftpaccess group and /usr/bin/nologin shell.

krizna@leela:~$ sudo useradd -m john -g ftpaccess -s /usr/sbin/nologin
krizna@leela:~$ sudo passwd john

Change ownership for the home directory.

krizna@leela:~$ sudo chown root /home/john

Create a folder inside home directory for writing and change ownership of that folder.

krizna@leela:~$ sudo mkdir /home/john/www
krizna@leela:~$ sudo chown john:ftpaccess /home/john/www

Now try to connect server using SFTP ( port : 22 ) and makesure Users can upload files to www directory and cannot access other folders outside home directory.setup FTP server ubuntu 14.04

setup-FTP-server-ubuntu-14-04

If you want use both FTP and SFTP together, please perform above steps ( Step 10 ) while creating users . For existing users, move them to ftpaccess group and create folder structure and ownership changes as below.

krizna@leela:~$ sudo usermod john -g ftpaccess -s /usr/sbin/nologin
krizna@leela:~$ sudo chown root /home/john
krizna@leela:~$ sudo mkdir /home/john/www
krizna@leela:~$ sudo chown john:ftpaccess /home/john/www

Now john can able to upload files to www folder using FTP as well as SFTP.
All the best.

Коды к Емайл форме 2

Это коды к статье Емайл формa, кэпча и антиспам.

Download: mail2.tar.gz

captcha.css

body {
margin: 0;
padding: 0;
display:inline-block;
}

body:after{
 display:none;
 content: url(/mail/refresh1.png) url(/mail/refresh2.png);
}

table {
margin: 0;
padding: 0;
height: 40px;
border: 0;
}

td {
margin: 0;
padding: 0;
height: 40px;
border: 0;
outline: 0;
}

img {
display:inline-block;
vertical-align:top;
}

input {
    background:url(/mail/refresh1.png) no-repeat;
    cursor:pointer;
    width: 40px;
    height: 40px;
    border:0 none !important;
}

input:hover {
    background:url(/mail/refresh2.png) no-repeat;
}

input:focus {
    border:none !important;
    outline: 0 !important;
    }

input::-moz-focus-inner {border:0;}

compose.css

body {
background-color: none;
color: white;
font-family: Verdana;
font-size: 14px;
margin: 0;
padding: 0;
}

h1 {
font-family: Tahoma;
font-size: 20px;
}

input {
display:inline-block;
vertical-align:top;
}

table {
margin: 0;
padding: 0;
border: 0;
}

td {
  padding-top: 0;
  padding-bottom: 0;
  display:table-cell;
}

iframe {
margin: 0;
padding: 0;
border: 0;
}

compose.html

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Compose</title>

</head>
<body>

<!-- === Копируй отсюда  === -->
<iframe src="/cgi-bin/compose.py" width="500" height="300" frameBorder="1"></iframe> 
<!-- === и досюда  ========= -->

</body>
</html>

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="refresh" content="0;url=/mail/compose.html">
  <link rel="canonical" href="/mail/compose.html"/>
  <title>Home</title>
</head>
<body>

<a href="/mail/compose.html">Home</a>

</body>
</html>

response.css

body {
background-color: darkmagenta  ;
color: white;
font-family: Verdana;
font-size: 14px;
}

h1 {
font-family: Tahoma;
font-size: 20px;
}

response.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <base target="_parent" />
<link rel="stylesheet" type="text/css" href="response.css">

<title>Спасибо</title>

</head>
<body>

<h1>Thank you</h1>Name: aaa<br>Email: a@gmail.com<br>Subject: done<br><br>done

</body>
</html>

settings.txt

path_blocks = /var/www/html/mail/blocks.txt
path_font = /var/www/html/mail/alfphabet.ttf
path_mail_dir = /var/www/html/mail/
path_response = /var/www/html/mail/response.html
path_template = /var/www/html/mail/template.txt
path_tokens = /var/www/html/mail/tokens.txt

N_tokens = 50

url_captcha_css = /mail/captcha.css
url_compose_css =/mail/compose.css
url_mail_dir = /mail/
url_mail_cgi = /cgi-bin/mail_alex/
url_open = /wordpress/index.php/response

code_bg_color = (253, 0, 211, 255)
code_dots_color = (0, 0, 0, 255)
code_dots_n = 3000
code_text_color = (255, 255, 255, 255)

email_to = vasqpupkin@mail.ru
sender_name = Мой секси сайт
smtp_login = moisexisite@gmail.com
smtp_password = T&ldkwtE4P
smtp_port = 587
smtp_security_type = TLS
smtp_server = smtp.gmail.com

mail_form_width = 400

template.txt

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <base target="_parent" />
<link rel="stylesheet" type="text/css" href="response.css">

<title>Спасибо</title>

</head>
<body>

[msg]

</body>
</html>

captcha.py

#!/usr/bin/python
#-*-coding:utf-8-*-

path_settings='/var/www/html/mail/settings.txt'


import cgitb
cgitb.enable()

import cgi, os, base64, ast
import mail_f

path_mail_dir, url_mail_dir, path_tokens, url_captcha_css, code_text_color, code_bg_color, code_dots_color, code_dots_n, path_font = '','','','','','','','',''

if os.path.exists(path_settings):
 f=open(path_settings)
 s=f.read()
 f.close()
 
 L=s.split('\n')
 
 for item in L:
  if '=' in item:
   l=item.split('=')
   var=l[0].strip()
   val=l[1].strip()
   
   if var=='path_mail_dir':
    path_mail_dir = val
   elif var=='url_mail_dir':
    url_mail_dir = val
   elif var=='path_tokens':
    path_tokens = val
   elif var=='url_captcha_css':
    url_captcha_css = val
   elif var=='code_text_color':
    code_text_color  = ast.literal_eval(val)
   elif var=='code_bg_color':
    code_bg_color  = ast.literal_eval(val)
   elif var=='code_dots_color':
    code_dots_color  = ast.literal_eval(val)
   elif var=='code_dots_n':
    code_dots_n  = int(val) 
   elif var=='path_font':
    path_font = val
   
else:
 print 'Content-type: text/html\n\n'
 print '<!doctype html>'
 print 'Not found: settings.txt'
 sys.exit()
 

T = mail_f.Code(path_mail_dir, url_mail_dir, code_text_color, code_bg_color, code_dots_color, code_dots_n, path_font)

path_out=T[0]
code_txt=T[1]


with open(path_out, "rb") as image_file:
    s = base64.b64encode(image_file.read())

with open(path_tokens, "a") as f:
    f.write(code_txt+'\n')

if os.path.exists(path_out):
 os.remove(path_out)

img='<img src="data:image/png;base64,'+s+'" height="40" width="120" alt="" title="Enter code">'


print 'Content-type: text/html\n\n'
print '<!doctype html>'

print '<html lang="en">'
print '<head>'
print '<meta charset="utf-8">'
print '<link rel="stylesheet" type="text/css" href="'+url_captcha_css+'">'
print '<title>Captcha</title>'
print '</head>'
print '<body>'
 
print '<form action="/cgi-bin/captcha.py" method="post">'
print '<table>'
print '<tr><td>'
print img
print '</td><td>'
print '<input type="submit" name="" value="">'
print '</td></tr></table>'
print '</form>'

print '</body>'
print '</html>'

compose.py

#!/usr/bin/python
#-*-coding:utf-8-*-

path_settings='/var/www/html/mail/settings.txt'


import cgitb
cgitb.enable()

import cgi, os, sys

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import mail_f

url_compose_css, mail_form_width = '',''


if os.path.exists(path_settings):
 f=open(path_settings)
 s=f.read()
 f.close()
 
 L=s.split('\n')
 
 for item in L:
  if '=' in item:
   l=item.split('=')
   var=l[0].strip()
   val=l[1].strip()
   
   if var=='url_compose_css':
    url_compose_css = val
   elif var=='mail_form_width':
    mail_form_width  = int(val) 
   
else:
 print 'Content-type: text/html\n\n'
 print '<!doctype html>'
 print 'Not found: settings.txt'
 sys.exit()
 

################################


print 'Content-type: text/html\n\n'

print '<!doctype html>'

print '<html lang="en">'
print '<head>'
print '<meta charset="utf-8">'
print '<link rel="stylesheet" type="text/css" href="'+url_compose_css+'">'
print "<base target='_parent' />"
print '<title>Compose</title>'
print '</head>'
print '<body>'
 

T=mail_f.mail_form_fields()

print '<form style="width: '+str(mail_form_width)+'px;" '+T[6]+'>'
print 'Name:<br>'
print '<input '+T[0]+' style="width: 100%;" type="text"><br><br>'
print 'Email:<br>'
print '<input '+T[1]+' style="width: 100%;" type="text" pattern="[^@]+@[^@]+\.[^@]+"><br><br>'
print 'Subject:<br>'
print '<input '+T[2]+' style="width: 100%;" type="text"><br><br>'
print 'Message:<br>'
print '<textarea '+T[3]+' style="width: 100%; height: '+str(mail_form_width/2.0)+'px;"></textarea><br>'

print '<table width="100%">'
print '<tr valign="middle">'
print '<td align="right">'
print 'Enter&nbsp;code:&nbsp;'
print '</td>'
print '<td>'
print '<input '+T[4]+' maxlength="6" size="7" type="text" pattern="[A-Z]{6}">'
print '&nbsp;</td>'
print '<td align="right">'
print '     <table>'
print '     <tr>'
print '     <td>'
print '     <iframe '+T[5]+' marginwidth="0" marginheight="0" hspace="0"  vspace="0" frameborder="0" scrolling="no" height="45" width="160"></iframe>'
print '     </td>'
print '     </tr>'
print '     </table>'
print '</td>'
print '</tr>'
print '<tr>'
print '<td></td>'
print '<td></td>'
print '<td align="right"><input value="Submit" type="submit"></td>'
print '</tr>'
print '</table>'
print '</form>'
print '</body>'
print '</html>'

mail_f.py

#!/usr/bin/python
#-*-coding:utf-8-*-

""" Функции для Мэил"""

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import random, string


def mail_form_fields():
 return ('name="name"', 'name="from"', 'name="subject"', 'name="message"', 'name="code"', 'src="/cgi-bin/captcha.py"', 'action="/cgi-bin/send.py" method="post"')


def Code(path_mail_dir, url_mail_dir, code_text_color, code_bg_color, code_dots_color, code_dots_n, path_font):
 """Random Code Generator"""
 size=6
 chars=string.ascii_uppercase
 code_txt=''.join(random.choice(chars) for _ in range(size))

 # Random string -----------------------

 img_width=120
 img_height=40
 img_font_size = 20
 img_padding=20


 path_out=path_mail_dir+code_txt+'.png'

 # Code Text  -------------------------

 img = Image.new("RGBA", (img_width, img_height), code_bg_color)
 draw = ImageDraw.Draw(img)


 i=0
 while i< code_dots_n:
  draw.point((random.randrange(5, img_width-5) , random.randrange(5, img_height-5) ), code_dots_color)
  i=i+1

 font = ImageFont.truetype(path_font, img_font_size)
 w, h = draw.textsize(code_txt, font)
 img_padding_hor=(img_width-w)/2.0
 img_padding_vert=(img_height-h)/2.0

 draw.text((img_padding_hor, img_padding_vert), code_txt, fill=code_text_color, font=font)

 img.save(path_out)
 
 return(path_out, code_txt)

send.py

#!/usr/bin/python
#-*-coding:utf-8-*-

path_settings='/var/www/html/mail/settings.txt'


import cgitb
cgitb.enable()

import cgi
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import os, time, re, sys

sender_name, email_to , smtp_security_type, smtp_server , smtp_port, smtp_login , smtp_password, path_template, path_response, path_blocks, url_compose_css, url_open , path_tokens, N_tokens = '','','','','','','','','','','','','',''


form = cgi.FieldStorage()
Errors=[]

Name, From, Subject, Message, Code = '','','','', ''
a, b, c, d = '','','',''
http_user_agent, remote_addr, http_referer = '', '', ''

if os.path.exists(path_settings):
 f=open(path_settings)
 s=f.read()
 f.close()
 
 L=s.split('\n')
 
 for item in L:
  if '=' in item:
   l=item.split('=')
   var=l[0].strip()
   val=l[1].strip()
   
   if var=='sender_name':
    sender_name = val
   elif var=='email_to':
    email_to = val
   elif var=='smtp_security_type':
    smtp_security_type = val
   elif var=='smtp_server':
    smtp_server = val
   elif var=='smtp_port':
    smtp_port = int(val) 
   elif var=='smtp_login':
    smtp_login = val
   elif var=='smtp_password':
    smtp_password = val
   elif var=='path_template':
    path_template = val
   elif var=='path_response':
    path_response = val
   elif var=='path_blocks':
    path_blocks = val
   elif var=='url_compose_css':
    url_compose_css = val
   elif var=='url_open':
    url_open = val
   elif var=='path_tokens':
    path_tokens = val
   elif var=='N_tokens':
    N_tokens = int(val)

else:
 print 'Content-type: text/html\n\n'
 print '<!doctype html>'
 print 'Not found: settings.txt'
 sys.exit()


try:
 http_user_agent=cgi.escape(os.environ["HTTP_USER_AGENT"])
except:
 http_user_agent='none'
try:
 remote_addr=cgi.escape(os.environ["REMOTE_ADDR"])
except:
 remote_addr='none'
try:
 http_referer=cgi.escape(os.environ["HTTP_REFERER"])
except:
 http_referer='none'
 
 
 

try:
 Name=form['name'].value.strip()
 Name=re.sub(r'<[^>]*?>', '', Name)
 a='Name: '+ Name
 if len(Name)==0:
  Errors.append('Name: none')
except:
 Errors.append('Name: none')
try:
 From = form['from'].value.strip()
 From = re.sub(r'<[^>]*?>', '', From)
 b='Email: '+ From
except:
 Errors.append('Email: none')
try:
 Subject=form['subject'].value.strip()
 Subject=re.sub(r'<[^>]*?>', '', Subject)
 c='Subject: '+ Subject
except:
 Errors.append('Subject: none')
try:
 Message = form['message'].value.strip()
 #Message = re.sub(r'<[^>]*?>', '', Message)
 
 d= Message.strip()
 

except:
 Errors.append('Message: none')

try:
 Code = form['code'].value.strip()
except:
 Errors.append('Error: code mismatch')


if len(Errors) == 0:
 EMAIL_REGEX = re.compile(r"[^@]+@[^@]+\.[^@]+")
 if not EMAIL_REGEX.match(From):
  Errors.append('Email is invalid: '+From)

if len(Errors) == 0:
 if os.path.exists(path_tokens)==False:
  Errors.append('Error: code mismatch')
 else:
  f=open(path_tokens, 'r')
  s=f.read()
  f.close()
  
  L=s.split()
  
  if Code not in L:
   Errors.append('Error: code mismatch')
  L.reverse()
  i=0
  l=[]
  OUT=[]
  for line in L:
   if i < N_tokens:
    if len(line)>0:
     OUT.append(line)
     i=i+1
  OUT.reverse()
  if len(OUT) >0:
   f=open(path_tokens, 'w')
   for line in OUT:
    f.write(line+'\n')
   f.close()



html='<h1>Thank you</h1>'+a+'<br>'+b+'<br>'+c+'<br>'*2+d.replace('\n', '<br>')

if len(Errors) == 0:
 try:
  msg = MIMEMultipart()
  msg['From'] = sender_name+' <'+smtp_login+'>'
  msg['Reply-To'] = Name+' <'+From+'>'
  msg['To'] = email_to
  msg['Subject'] = Subject
  msg['Date'] = time.strftime("%c")
  
  Message= \
Message+'\n\n'\
+'HTTP_USER_AGENT = '+http_user_agent+'\n'\
+'REMOTE_ADDR = '+remote_addr+'\n'\
+'HTTP_REFERER = '+http_referer+'\n\n'\
  
  msg.attach(MIMEText(Message, 'plain'))

  # Опции для SMTP сервера ---------
  
  if smtp_security_type =='TLS':
   server = smtplib.SMTP(smtp_server, smtp_port)
   server.starttls()
  
  if smtp_security_type =='SSL':
   server = smtplib.SMTP_SSL(smtp_server, smtp_port)
   
  server.ehlo()
  server.login(smtp_login, smtp_password)
  text = msg.as_string()
  
  # Checking blocks.txt ----------
  block='no'
  if os.path.exists(path_blocks):
   f=open(path_blocks, 'r')
   s=f.read()
   f.close()
   
   H=[http_user_agent, remote_addr, http_referer] # Headers
   L=s.split('\n')
   
   for item in L:
    h=''
    v=''
    if '=' in item:
     l=item.split('=')
     h=l[0].strip()
     v=l[1].strip()
     if v in H:
      block='yes'
      break
      
  if block=='no':
   server.sendmail(From, email_to, text)
   
  server.close()
  
  #----------------------------------
  
 except Exception as e:
  
  i=0
  for item in e:
   
   item=str(item)
   if i==0:
    item='Error: '+item
   
   item=item.replace('<', '&lt;')
   item=item.replace('>', '&gt;')
   
   Errors.append(item)
   i=1+1

if len(Errors)>0:
 html='<h1>Please correct</h1>'
 for item in Errors:
  html=html+item+'<br>'
 html=html+'<br>Email delivery failed.'

f=open(path_template, 'r')
s=f.read()
f.close()

s=s.replace('[msg]', html)

f=open(path_response, 'w')
f.write(s)
f.close()

print 'Content-type: text/html\n\n'
print '<meta http-equiv="refresh" content="0;url='+url_open+'">'
print '<link rel="canonical" href="'+url_open+'"/>'

iframe.html

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>Response</title>
</head>
<body>
 
<!-- === Копируй отсюда  === -->
<iframe src="/mail/response.html" width="500" height="300" frameBorder="0"></iframe> 
<!-- === и досюда  ========= -->

</body>
</html>

Емайл формa, кэпча и антиспам

Эта статья является дополнением к Как бороться со спамом на домашнем вэб-сервере и модернизированными инструкциями для Как послать Емайл с домашнего веб-сайта.

Коды и скачать

Мы также создаем две страницы Contact и Response, только в этот раз в первую страницу кладем iframe со ссылкой на экзекьютабл источник.

Contact

Response

Питонные файлы кладем в /cgi-bin, а все остальные в /mail [1].

Описание файлов

Папка Файл Permissions Описание
/mail a+rwx
alfphabet.ttf a+r Шрифт для кэпчи
blocks.txt a+r Заблокированные отправители
captcha.css a+r
compose.css a+r
compose.html a+r
index.html a+r Редирект на страницу Contact
refresh1.png a+r Кнопка на кэпче
refresh2.png a+r Кнопка на кэпче hover
response.css a+r
response.html a+r Автоматически генерируемый файл на основе  template.txt
settings.txt a+r Всевозможные опции для программы
template.txt a+r Шаблон для response.html. Вы можете свою template придумать.
tokens.txt a+rw Куда кэпча записывает коды для хранения
/cgi-bin
captcha.py a+rx Кэпча
compose.py a+rx Загружает HTML форму
mail_f.py a+r Программные функции
send.py a+rx Посылает письмо

settings.txt

SYNTAX

Variable = value

В settings.txt можно менять значения переменных: путь, URL, цвет кэпчи, фонт кода и тд.

Описание Settings

File Variable Value Значение
compose.py mail_form_width 400 Ширина майл формы
url_compose_css /mail/compose.css
captcha.py captcha_bg_color (253, 0, 211, 255) Цвет фона кодовой картинки
captcha_dots_color (0, 0, 0, 255) Цвет точек кодовой картинки
captcha_dots_n 3000 Количество хаотичных точек на кодовой картинке
captcha_text_color (255, 255, 255, 255) Цвет букв кодовой картинки
captcha_width 120  Ширина картинки
captcha_height 40  Высота картинки
captcha_font_size 20  Размер шрифта
captcha_padding 20  Пэддинг
path_font /var/www/html/mail/alfphabet.ttf Шрифт для кодовой картинки
path_mail_dir /var/www/html/mail/
url_mail_cgi /var/www/html/cgi-bin/mail/ Папкa с скриптами в /cgi-bin
path_tokens /var/www/html/mail/tokens.txt
url_captcha_css /mail/captcha.css
url_mail_dir /mail/ Слаш в конце на всех url_ необходим, если папка
send.py N_tokens 50 Количество кодов для хранения в tokens.txt
email_to vasqpupkin@mail.ru Получатель письма из майл формы
path_blocks /var/www/html/mail/blocks.txt
path_response /var/www/html/mail/response.html
path_template /var/www/html/mail/template.txt
sender_name Мой секси сайт Это то, что появится в письме в заголовке “От кого” при получении.
smtp_login moisexisite@gmail.com Логин на Гугле
smtp_password z63T<E4P Пароль на Гугле
smtp_port 587 SMTP порт
smtp_security_type TLS Секьюрити: TLS или SSL
smtp_server smtp.gmail.com Имя SMTP сервера
url_open /wordpress/index.php/response URL страницы Response

 

blocklist.txt

SYNTAX

Header = value

Когда вы получаете письмо со своего сайта, заголовки REMOTE_ADDR, HTTP_USER_AGENT, HTTP_REFERER прикрепляются к концу письма, и, если вы хотите кого-нибудь блокировать, то просто скопируйте строчку с одним или несколькими заголовками и поместите ее в blocklist.txt [2].

[1] Примечания

Path_

Файлы с флагом path_ не обязательно хранить в папке /mail и даже желательно класть их за пределы /var/www/html, чтоб никто через порт 80 не смог их прочитать.

Url_

Файлы с флагом url_ используются вэб-сервером и должны находиться в пределах /var/www/html.

Как бороться со спамом на домашнем вэб-сервере

Я написал статью Как послать Емайл с домашнего веб-сайта, где описал основной принцип отправки электронной почты с помощью SMTP сервера GMail, но ничего не сказал о защите от спама.

Теоретически если спамбот найдет нашу страницу Contact, то он может выделить из нее реквизиты емайл формы, и спаммер станет слать нам кипы мусора, прямо через URL:

http://mysexysite/cgi-bin/sendmail.py?name=Вася Пупкин&from=vasqpupkin@mail.ru&subject=Грязный спам&message=Читай блог Мисс Трамел и станешь дураком

Мы этого естественно не хотим.

Мы обезопасим себя тем, что:

  • спрячем HTML в Питонный код
  • сделаем картиночную кэпчу
  • будем вручную блокировать спаммеров

Программный код вместо HTML

Предположительно спамботам труднее ориентироваться в программном коде, чем в чистом HTML.

HTML

Python

Не совсем одно и то же.

Картиночная кэпча

Кэпча генерирует код, который показывается юзеру в виде картинки, чтоб он подтвердил его вручную. Если юзерский инпут не совпадет с кодом на сервере, письмо не отправляется. Картинка измалевана точками, чтоб спаммерские программы OCR не распознали текст, и зашифрована кодировкой Base64, чтобы бот не скачал ее по URL.

Ручной антиспам

Сервер генерирует ряд заголовков, которые могут идентифицировать спаммера:

REMOTE_ADDR IP, с которого осуществлен запрос на наш сайт.
HTTP_USER_AGENT Программа, с которой осуществлен запрос на наш сайт. У спаммеров агенты смешно называются: BlackWidow, ChinaClaw, Go!Zilla, Mister, Papa, Zeus и тд.
HTTP_REFERER Домен, с которого произошел запрос на наш сайт. В идеале это должен быть наш домен, потому что подразумевается, что посетители нашего сайта будут слать нам письма с нашего сайта, а не с Лубянки или Огарева 6.

Мы атрибуты надоедливого товарища положим в файл, который будет проверяться перед каждой отправкой послания, и, если спаммер там, то емайл не отправится, хотя умник не заметит ничего подозрительного, поскольку страница перезагрузится, как обычно. Мы ему не скажем, чтоб он и дальше думал, что самый умный.

Стирание HTML тагов

Некоторые еще советуют стирать HTML таги из письма, но я не вижу в этом особого смысла. Просто получишь спам без тагов, только и всего. Если спаммера блокировать на основе тагов, тогда и сам не пошлешь никакой ссылки. Впрочем, смотрите сами.

Далее:
Емайл формa, кэпча и антиспам

Домен для домашнего веб-сервера

Чтоб показывать страницы в интернете, надо иметь доменное имя, а если вэб-сервер стоит дома, то и службу корректировки динамического IP. Домен – это последовательность букв типа http://google.com, а IP – последовательность цифр – http://74.125.224.72, обозначающих номер компьютера. Домен используется юзером, потому что его проще запомнить, а сам компьютер использует цифры для соединения с другими компьютерами в сети. Таким образом буквы домена подразумевают под собой цифры IP, которые в идеале неизменны – статичный IP. Но фактически у домашнего пользователя IP динамический, который он получает от раутера провайдера и который все время меняется. Чтоб домен каждый раз попадал на правильный номер, его периодически надо переассоциировать с новым IP. Все это делается за деньги, но бывают и исключения, как, например, Duck DNS. О нем я и расскажу.

Duck DNS – без балды бесплатная DDNS (Dynamic DNS) служба, которая обеспечивает корректировку динамического IP домашнего компьютера в соответствии с выбранным субдоменом при помощи скрипта, который каждые 5 минут проверяет состояние вашего публичного IP без обязательной перерегистрации, уведомлений и другой скрытой коммерческо-рекламной лабуды.

Зарегистрируйтесь на Duck DNS, выберите субдомен – johnsmith, например. Интернетовский адрес вашего сайта фактически будет

johnsmith.duckdns.org.

Может, для сайта кабмина овальной гранотовидной палаты сбоку припека в виде duckdns не совсем сексуальна, но рядовому юзеру, чтоб послать ссылку корешам на новые фотки, вполне сойдет. Eсли такой расклад вас не устраивает все-равно, тогда надо зарегистрировать реальный коммерческих домен и сделать редирект на адрес johnsmith.duckdns.org – домен форвардинг, как еще говорят.

Скачайте установочный скрипт, соответствующий вашей операционной системе – Линукс GUI, например.

Запомни имя домейна и токен:

johnsmith.duckdns.org
2b29bb18-3af9-49a1-9f14-84a11e4ebc08

На Линуксе соверши ряд команд:

sudo apt-get install zenity cron curl
chmod +x duck-setup-gui.sh
./duck-setup-gui.sh

Запустилась GUI, куда надо ввести имя домейна и токен.

В домашней директории появилась папка ~/duckdns. В ней находятся лог файл и скрипт для апдейта вашего IP адреса как работа cron каждые 5 минут.

~/duckdns/duck.log
~/duckdns/duck.sh

Cron job можно видеть командой:

crontab -l

Теперь надо настроить порт форвардинг.

Далее:

Порт форвардинг
Статичный IP

Порт форвардинг

Когда стоит раутер, он выпускает запросы из локальной сети или отдельно стоящего комьютера в интернет, но не впускает никакие сигналы извне. Для этого нужно открыть порт – дырку с номером. Для веб-сервера это порт 80. Вот и нужно сказать вашему раутеру на какой локальный IP ему перенаправлять трафик, идущий через порт 80.

У меня раутер ASUS RT-N53, для него я и дал пример. Для каждой модели требуется своя конфигурация, которую вы найдете на сайте Port Forward.

Конфигурация раутера

Логин в раутер и пойди:

WAN > Virtual Server / Port Forwarding

Измени настройки:

Enable Port Forwarding Yes
Famous Server List HTTP
Protocol BOTH
Add / Delete +

Далее:

Статичный IP

Статичный IP для домашнего веб-сервера

Для веб-сервера нужен статичный IP. При каждой перезагрузке, компьютер запрашивает у раутера новый IP, и когда у вас налажен порт форвардинг, то раутер будет перенаправлять трафик на IP, которого фактически нет, и ничего не будет работать. Вот и надо сказать компьютеру, на котором стоит веб-сервер, какой IP ему все время запрашивать.

У меня инструкции для Линукса на примере Гном Нетуорк Менеджера.

Нам нужно определить:

Ваш IP
Netmask
Gateway
DNS Server

В терминале издайте команду:

nm-tool

Примечание:

В Ubuntu 15.04 nm-tool почему-то уже не присутствует, а был такой удобный инструмент. Но его можно заполучить вручную из репо Убунту 14.04. Инструкции для 32-битной системы следующие:

mkdir nm-tool
cd nm-tool
wget http://security.ubuntu.com/ubuntu/pool/main/n/network-manager/network-manager_0.9.8.8-0ubuntu7.1_i386.deb
ar xvf *
tar xvf dat*

Экзекьютабл вы найдете в ~/nm-tool/usr/bin.

 
Появятся данные

IPv4 Settings:
    Address:        192.168.1.67
    Prefix:         24 (255.255.255.0)
    Gateway:        192.168.1.254

    DNS:            192.168.1.254

где

  • Address – ваш текущий IP адрес
  • Prefix – адрес в скобках – нетмаск
  • Gateway – гейувей или адрес по умолчанию
  • DNS – ваш текущий DNS сервер

Теперь в терминале издайте команду

nm-connection-editor

В появившемся окне выберете:

Ethernet > Wired connection > Edit

static-ip-2

Пойдите в таб IPv4 Settings, выберите Method: Manual и поставьте опции из данных, которые мы получили:

Чтоб изменения возымели эффект надо или перезагрузить компьютер, или перезапустить сетевые службы:

sudo service resolvconf restart
sudo service networking restart

Как послать Емайл с домашнего веб-сайта

Чтоб послать на мыло, надо почтовый сервер. На домашнем компе иметь почтовый сервер – дело дорогое и неблагодарное, поэтому мы будем иметь не свой почтовый сервер.

Идея такая: мы заходим в свой эккаунт на GMail и оправляем емайл самому себе, но на другой адрес из простой HTML формы на нaшем сайте через интерпретатор Питона.

Лучше подключаться к GMail, чем Mail.ru. GMail отправляет без нареканий, а Mail.ru через раз и не без капризов – то отправитель неместный, то спам в пустом письме. Параноидные уроды.

Пререквизиты

Зарегистрируйте на GMail эккаунт с почтовым ящиком, например, misexysite@gmail.com.

Возьмем реквизиты SMTP сервера GMail:

Тип секьюрити TLS
SMTP сервер smtp.gmail.com
SMTP порт 587
Ваш логин misexysite@gmail.com
Ваш пароль z63)1Lg1

Определим:

Емайл адресата vasqpupkin@mail.ru
Имя отправителя Мой секси сайт

Также надо будет указать URL ответной страницы, которая откроется как подтверждение, что письмо отправлено.

open_url = '/mail/iframe.html'

Эти данные надо будет ввести в скрипт sendmail.py

Скрипт должен сразу заработать. Однако мы хотим, чтоб он работал в ВордПрессе и ДокуВики.

На сервере

Включаем модуль cgi, чтоб скрипты запускались:

sudo a2enmod cgi
sudo service apache2 restart

Директории, файлы и разрешения

Экзекьютабл sendmail.py должен быть в cgi-bin. Так требует Апачи – наш веб-сервер.

Делаем симлинк из директории /var/www/html к /usr/lib/cgi-bin

cd /var/www/html
sudo ln -s /usr/lib/cgi-bin

Создаем файл /usr/lib/cgi-bin/sendmail.py и меняем разрешение:

sudo touch /usr/lib/cgi-bin/sendmail.py
sudo chmod a+rwx /usr/lib/cgi-bin/sendmail.py

Открываем файл /usr/lib/cgi-bin/sendmail.py и скопопейстиваем.

Создаем в директории / нашего сервера папку mail и даруем ей разрешение на запись:

sudo mkdir /var/www/html/mail
sudo chmod a+rwx /var/www/html/mail

Создаем файлы /mail/response.css и /mail/template.txt и меняем разрешения:

sudo touch /var/www/html/mail/response.css
sudo touch /var/www/html/mail/template.txt

sudo chmod a+rw /var/www/html/mail/response.css
sudo chmod a+rw /var/www/html/mail/template.txt

Открываем /var/www/html/mail/response.css и скопипейстиваем.

Открываем /var/www/html/mail/template.txt и скопипейстиваем.

Интеграция с ВордПресс

В ВордПрессе создаем страницы Contact и Response.

Открываем Contact в текстовом режиме редактора и скопипейстиваем HTML форму.

Открываем Response в текстовом режиме редактора и скопипейстиваем iframe.

Для iframe можно изменить параметры width, height и border, если надо.

Копируем URL страницы Response и пейстим ее в скрипт sendmail.py на линии 23.

Идем на страницу Contact и нажимаем Submit.

Работает.

Посылаем что-нибудь.

Нормалек. Только расцветка не соответствует сексуальности сайта.

Открываем /mail/response.css и меняем:

background-color: white; на background-color: #2D002F;
и
color: black; на color: white;

Shift+Ctrl+R – force reload

Cool.

А теперь я – спаммер и пишу похабщину.

Букварь выучи сначала спамерша.

Страницу Response можно теперь спрятать.

Как спрятать страницу в WordPress

Интеграция с DokuWiki

На DokuWiki установка аналогичная, только требуется в Admin > Configuration Settings > Editing дать разрешение на показ HTML.

Ставим галочку и сохраняем.

Создаем страницы: Contact и Response.

На странице Contact в редакторе DW Edit пэйстим емайл форму, обрамленную тагами <html>...</html>.


Идем на страницу Response и вставляем iframe, обрамленную тагами <html>...</html>.

Вставляем URL страницы Response в sendmail.py скрипт

Идем в Contact и посылаем письмо:

Ссылку на страницу Response теперь можно стереть, чтоб посетители не нажимали.

А ссылку Contact можно поставить в навигационную панель.

Как сделать навигационную панель в Dokuwiki

 

Скрипты для Mail Form

Это скрипты, которые требуются для того, чтоб послать емайл с домашнего веб-сайта. Инструкции по их применению тут.

Скачать: mail.tar.gz

sendmail.py

#!/usr/bin/python
#-*-coding:utf-8-*-

#=============================================
# СМЕНИ НАСТРОЙКИ

sender= 'Мой секси сайт'  # Имя отправителя, которое появится в 
     # поле From (Oт кого)
email_to = "vasqpupkin@mail.ru"  # адрес, на который пойдет емайл

smtp_security_type='TLS'  # TLS или SSL
     # TLS для Gmail
     # SSL для Mail.ru
       
smtp_server = "smtp.gmail.com"  # название SMTP сервера
smtp_port= 587    # Порт SMTP сервера
smtp_login = "misexysite@gmail.com" # Твой логин на Mail.ru или Gmail
smtp_password="z63)1Lg1"  # Твой пароль


template='/var/www/html/mail/template.txt' # Путь к файлу templates.txt
response='/var/www/html/mail/response.html' # Путь к файлу response.html
open_url = '/mail/iframe.html'   # URL страницы с iframe.

#==============================================

import cgitb
cgitb.enable()

import cgi
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import time, re

form = cgi.FieldStorage()
Errors=[]

Name, From, Subject, Message = '','','',''
a, b, c, d = '','','',''

try:
 Name=form['name'].value.strip()
 a='Ваше имя: '+ Name
 if len(Name)==0:
  Errors.append('Ваше имя: не указано')
except:
 Errors.append('Ваше имя: не указано')
try:
 From = form['from'].value.strip()
 b='Ваш емайл: '+ From
except:
 Errors.append('Ваш емайл: не указан')
try:
 Subject=form['subject'].value.strip()
 c='Тема: '+ Subject
except:
 Errors.append('Тема: не указана')
try:
 Message = form['message'].value.strip()
 d= Message
except:
 Errors.append('Послание: отсутствует')

if len(Errors) == 0:
 EMAIL_REGEX = re.compile(r"[^@]+@[^@]+\.[^@]+")
 if not EMAIL_REGEX.match(From):
  Errors.append('Ваш емайл невалидный: '+From)

html='<h1>Спасибо за письмо</h1>'+a+'<br>'+b+'<br>'+c+'<br>'*2+d.replace('\n', '<br>')

if len(Errors) == 0:
 try:
  msg = MIMEMultipart()
  msg['From'] = sender+' <'+smtp_login+'>'
  msg['Reply-To'] = Name+' <'+From+'>'
  msg['To'] = email_to
  msg['Subject'] = Subject
  msg['Date'] = time.strftime("%c")
  msg.attach(MIMEText(Message, 'plain'))

  # Опции для SMTP сервера ---------
  
  if smtp_security_type =='TLS':
   server = smtplib.SMTP(smtp_server, smtp_port)
   server.starttls()
  
  if smtp_security_type =='SSL':
   server = smtplib.SMTP_SSL(smtp_server, smtp_port)
   
  server.ehlo()
  server.login(smtp_login, smtp_password)
  text = msg.as_string()
  server.sendmail(From, email_to, text)
  server.close()
  
  #----------------------------------
  
 except Exception as e:
  
  i=0
  for item in e:
   
   item=str(item)
   if i==0:
    item='Error: '+item
   
   item=item.replace('<', '&lt;')
   item=item.replace('>', '&gt;')
   
   Errors.append(item)
   i=1+1

if len(Errors)>0:
 html='<h1>Исправьте ошибки</h1>'
 for item in Errors:
  html=html+item+'<br>'
 html=html+'<br>Письмо не отправлено.'

f=open(template, 'r')
s=f.read()
f.close()

s=s.replace('[msg]', html)

f=open(response, 'w')
f.write(s)
f.close()

print 'Content-type: text/html\n\n'
print '<meta http-equiv="refresh" content="0;url='+open_url+'">'
print '<link rel="canonical" href="'+open_url+'"/>'

iframe.html

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>Response</title>
</head>
<body>
 
<!-- === Копируй отсюда  === -->
<iframe src="/mail/response.html" width="500" height="300" frameBorder="0"></iframe> 
<!-- === и досюда  ========= -->

</body>
</html>

response.css

body {
background-color: white;
color: black;
font-family: Verdana;
font-size: 14px;
}

h1 {
font-family: Tahoma;
font-size: 20px;
}

template.txt

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<link rel="stylesheet" type="text/css" href="response.css">
<title>Спасибо</title>
</head>
<body>

[msg]

</body>
</html>

mailform.html

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>Mail Form</title>
</head>
<body>
 
<h1>Напиши мне</h1>

<!-- === Копируй отсюда  === -->
<form action="/cgi-bin/sendmail.py" method="get">
Ваше имя:<br>
<input name="name" size="40" type="text"><br><br>
Ваш емайл:<br>
<input name="from" size="40" type="text"><br><br>
Тема:<br>
<input name="subject" size="40" type="text"><br><br>
Послание:<br>
<textarea cols="46" name="message" rows="10"></textarea><br><br>
<input value="Submit" type="submit"></form>
<!-- === и досюда  ========= -->

</body>
</html>